Swing - Painting tree and Jfreechart in one window - java

I have a program that I am writing and I need it to both draw a tree and plot its points.
The issue:
My paint seems to go under my graph/plot even though they are in two panels. What can I do so that they do not overlap. Maybe even a scroll bar?
Here is an example Left is with the graph overlapping, right is showing what is underneath.
Bonus:
What is a better way to draw the tree, some of the nodes overlap.
Code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import org.jfree.chart.*;
import org.jfree.chart.axis.Axis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
public class ui extends JFrame {
JPanel tp,chartPanel;
Tree t;
Node root;
Parser p;
double x = 0, y = 0;
int generation = 0;
int timeSeconds = 0;
double fitness = Double.MIN_VALUE;
int sizeX = 1000;
int sizeY = 1000;
int depth = 10;
public ui() {
super("Simple Tree");
setSize(sizeX, sizeY);
setDefaultCloseOperation(EXIT_ON_CLOSE);
tp = new TPanel();
tp.setLayout(new BorderLayout());
chartPanel = new TPanel();
chartPanel.setLayout(new BorderLayout());
//JButton genButton = new JButton("Generate Tree");
//tp.add(genButton);
add(tp);
add(chartPanel);
}
public ChartPanel GraphTree(Node n){
XYSeriesCollection dataSet = new XYSeriesCollection();
XYSeries series = new XYSeries("Data");
XYSeries actual = new XYSeries("Actual");
Parser p = new Parser();
for(double index = -10; index < 10; index+=0.1){
series.add(index, p.TreeOutputAtPoint(n,index));
}
dataSet.addSeries(series);
JFreeChart jc = ChartFactory.createXYLineChart("Tree Graph", "Input", "Output",dataSet,
PlotOrientation.VERTICAL, true, true, false);
ChartPanel cp = new ChartPanel(jc);
cp.setPreferredSize(new java.awt.Dimension(200, 500));
cp.setVisible(true);
chartPanel.add(cp, BorderLayout.SOUTH);
chartPanel.validate();
chartPanel.removeAll();
chartPanel.revalidate();
//tp.repaint();
return cp;
}
public void drawTree(Node r, int gen, double fit, int timeSec){
root = r;
p = new Parser();
generation = gen;
timeSeconds = timeSec;
fitness = fit;
}
class TPanel extends JPanel {
public TPanel() {
setPreferredSize(new Dimension(sizeX, sizeY));// fill whole frame
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(root != null){
Eval(root, g, sizeX/2, 100);
g.drawString("Generation: " + generation, 15, 100);
g.drawString("Time it took: " + timeSeconds + " seconds", 15, 120);
g.drawString("Fitness: " + fitness, 15, 140);
}
}
}
public static void Eval(Node input, Graphics g, int x, int y) {
g.drawString(input.data, x, y);
if (!input.leaf) {
g.drawLine(x, y + 5, x - 20, y + 20);
Eval(input.left, g, x - 30, y + 30);
if (!Utility.isUnary(input.data)) {
g.drawLine(x, y + 5, x + 20, y + 20);
Eval(input.right, g, x + 30, y + 30);
}
}
}
}
https://github.com/kevkid/GeneticAlgorithmTest/blob/master/GeneticAlgorithmTest/src/ui.java
Any help would be appreciated.

Related

Gradiently shifting colors in Swing?

So I add 8 TextFields and wanna set their background colors. My idea is to set the first one to red (255, 0, 0) the last one to blue (0, 0, 255) and the 8 (or any number actually) others gradient between these. I'm trying to figure out how to solve it in terms of "If the 'next' variable is 0 increase this variable with same amount as previous variable is decreasing with"
So it could look like in each iteration:
setBackground(255, 0, 0);
setBackground(191, 63, 0);
setBackground(127, 127, 0);
...
setBackground(0, 0, 255);
Now I wanna try and fit this way of increase and decreasing into a for loop that will iterate n times where n is number of TextFields (now 8 for simplicity). Anyone know if there's a clever solution to this?
MRE:
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Apple{
public Apple(int width, int height) {
SwingUtilities.invokeLater(() -> initGUITest(width, height));
}
public void initGUITest(int width, int height) {
JFrame frame = new JFrame();
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
JPanel panel = new JPanel();
GridLayout gl = new GridLayout(10, 1);
panel.setLayout(gl);
frame.add(panel);
for(int i = 0; i < 8; i++) {
JTextField jtf = new JTextField("Track " + (i + 1));
jtf.setBackground(new Color(255, 0, 0)); //Start color
panel.add(jtf);
}
}
public static void main(String args[]) {
Apple a = new Apple(300, 300);
}
}
Checking if an value is zero and incrementing or decrementing a value from there is inefficient.
There are 2 ways to go about this
Linear
you calculate an blend value which is (i/stepSize) and use that to linearly interpolate between the start and end value as follows
intermediateColor[0]=(int)(start.getRed()+(end.getRed()-start.getRed())*alpha);
intermediateColor[1]=(int)(start.getGreen()+(end.getGreen()-start.getGreen())*alpha);
intermediateColor[2]=(int)(start.getBlue()+(end.getBlue()-start.getBlue())*alpha);
conversion of blend to float is necessary for interpolation to work here is logic
private static void layout1(JFrame frame)
{
Color
start=Color.RED,
end=Color.BLUE;
int[] intermediateColor=new int[3];
int steps=8;
float alpha;
for(int i=0;i<=steps;i++)
{
JTextField field=new JTextField(10);
alpha=((float)i/steps);
intermediateColor[0]=(int)(start.getRed()+(end.getRed()-start.getRed())*alpha);
intermediateColor[1]=(int)(start.getGreen()+(end.getGreen()-start.getGreen())*alpha);
intermediateColor[2]=(int)(start.getBlue()+(end.getBlue()-start.getBlue())*alpha);
field.setBackground(new Color(intermediateColor[0],intermediateColor[1],intermediateColor[2]));
frame.add(field);
}
}
Output :
KeyFrames
An more complicated example involves using key frames where you dynamically change the start and end points based on your i value
Here are the keyframes
int[] checkPoints={0,2,4,6,8};
Color[] colors={Color.RED,Color.GREEN,Color.BLUE,Color.YELLOW,Color.MAGENTA};
what this means is that for
checkboxes 0->2 interpolate between RED & GREEN
checkboxes 3->4 interpolate between GREEN & BLUE
checkboxes 5->6 interpolate between BLUE & YELLOW
checkboxes 7->8 interpolate between YELLOW & MAGENTA
The logic lies in this code
//loop through all checkpoints
for(int j=0;j<checkPoints.length-1;j++)
{
//check if i lies in between these 2 checkpoints
if(i>=checkPoints[j] && i<=checkPoints[j+1])
{
//interpolate between this & the next checkpoint
checkPoint=j;
start=colors[checkPoint];
end=colors[checkPoint+1];
//distance of i from start checkpoint/ total distance between checkpoints
alpha=(float)(i-checkPoints[checkPoint])/(checkPoints[checkPoint+1]-checkPoints[checkPoint]);
}
}
Here is the full code
public class Test
{
public static void main(String[] args)
{
JFrame frame=new JFrame("TEST");
frame.setContentPane(new JPanel(new FlowLayout(FlowLayout.LEADING,10,0)));
layout2(frame);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static void layout1(JFrame frame)
{
Color
start=Color.RED,
end=Color.BLUE;
int[] intermediateColor=new int[3];
int steps=8;
float alpha;
for(int i=0;i<=steps;i++)
{
JTextField field=new JTextField(10);
alpha=((float)i/steps);
intermediateColor[0]=(int)(start.getRed()+(end.getRed()-start.getRed())*alpha);
intermediateColor[1]=(int)(start.getGreen()+(end.getGreen()-start.getGreen())*alpha);
intermediateColor[2]=(int)(start.getBlue()+(end.getBlue()-start.getBlue())*alpha);
field.setBackground(new Color(intermediateColor[0],intermediateColor[1],intermediateColor[2]));
frame.add(field);
}
}
private static void layout2(JFrame frame)
{
int[] checkPoints={0,2,4,6,8};
Color[] colors={Color.RED,Color.GREEN,Color.BLUE,Color.YELLOW,Color.MAGENTA};
int[] intermediateColor=new int[3];
int steps=8;
int checkPoint;
float alpha=0;
Color start=null,end=null;
for(int i=0;i<=steps;i++)
{
JTextField field=new JTextField(10);
for(int j=0;j<checkPoints.length-1;j++)
{
if(i>=checkPoints[j] && i<=checkPoints[j+1])
{
checkPoint=j;
start=colors[checkPoint];
end=colors[checkPoint+1];
alpha=(float)(i-checkPoints[checkPoint])/(checkPoints[checkPoint+1]-checkPoints[checkPoint]);
}
}
intermediateColor[0]=(int)(start.getRed()+(end.getRed()-start.getRed())*alpha);
intermediateColor[1]=(int)(start.getGreen()+(end.getGreen()-start.getGreen())*alpha);
intermediateColor[2]=(int)(start.getBlue()+(end.getBlue()-start.getBlue())*alpha);
field.setBackground(new Color(intermediateColor[0],intermediateColor[1],intermediateColor[2]));
frame.add(field);
}
}
}
Output :
So, any number of ways you might do this, but for me, personally, I'd look towards using some kind of "blending" algorithm which would allow you to establish the "range" of colors you want and then based on some value (ie a index or percentage), generate a color which is blend of those colors (within the range).
For example...
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.text.NumberFormat;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
ColorBlender blender = new ColorBlender(new float[] {0, 1}, new Color[] {Color.RED, Color.BLUE});
for (int index = 0; index < 8; index++) {
Color color = blender.blendedColorAt(index / 7f);
System.out.println(color);
JTextField textField = new JTextField(10);
textField.setBackground(color);
add(textField, gbc);
}
}
}
public class ColorBlender {
private float[] fractions;
private Color[] colors;
public ColorBlender(float[] fractions, Color[] colors) {
this.fractions = fractions;
this.colors = colors;
}
public Color blendedColorAt(float progress) {
Color color = null;
if (fractions != null) {
if (colors != null) {
if (fractions.length == colors.length) {
int[] indicies = getFractionIndicies(fractions, progress);
float[] range = new float[]{fractions[indicies[0]], fractions[indicies[1]]};
Color[] colorRange = new Color[]{colors[indicies[0]], colors[indicies[1]]};
float max = range[1] - range[0];
float value = progress - range[0];
float weight = value / max;
color = blend(colorRange[0], colorRange[1], 1f - weight);
} else {
throw new IllegalArgumentException("Fractions and colours must have equal number of elements");
}
} else {
throw new IllegalArgumentException("Colours can't be null");
}
} else {
throw new IllegalArgumentException("Fractions can't be null");
}
return color;
}
protected int[] getFractionIndicies(float[] fractions, float progress) {
int[] range = new int[2];
int startPoint = 0;
while (startPoint < fractions.length && fractions[startPoint] <= progress) {
startPoint++;
}
if (startPoint >= fractions.length) {
startPoint = fractions.length - 1;
}
range[0] = startPoint - 1;
range[1] = startPoint;
return range;
}
protected Color blend(Color color1, Color color2, double ratio) {
float r = (float) ratio;
float ir = (float) 1.0 - r;
float rgb1[] = new float[3];
float rgb2[] = new float[3];
color1.getColorComponents(rgb1);
color2.getColorComponents(rgb2);
float red = rgb1[0] * r + rgb2[0] * ir;
float green = rgb1[1] * r + rgb2[1] * ir;
float blue = rgb1[2] * r + rgb2[2] * ir;
if (red < 0) {
red = 0;
} else if (red > 255) {
red = 255;
}
if (green < 0) {
green = 0;
} else if (green > 255) {
green = 255;
}
if (blue < 0) {
blue = 0;
} else if (blue > 255) {
blue = 255;
}
Color color = null;
try {
color = new Color(red, green, blue);
} catch (IllegalArgumentException exp) {
NumberFormat nf = NumberFormat.getNumberInstance();
System.out.println(nf.format(red) + "; " + nf.format(green) + "; " + nf.format(blue));
exp.printStackTrace();
}
return color;
}
}
}
Okay, but I want to blend between three colors
Okay, not an issue. Simply add another "stop" and the color for that stop, for example...
ColorBlender blender = new ColorBlender(new float[] {0f, 0.5f, 1f}, new Color[] {Color.RED, Color.YELLOW, Color.BLUE});
will produce...
Want to add more fields? No worries, just change Color color = blender.blendedColorAt(index / 7f); to so that 7f becomes the number of expected fields - 1 (remember, we're starting the index at 0 😉)
Here is a class that can generate a series of colors that can transition from one color to another for a given number of steps.
Simple usage would be:
ColorTransition ct = new ColorTransition(Color.RED, Color.BLUE, 8);
If you need multiple transitions you could do:
ColorTransition ct = new ColorTransition(Color.RED, Color.BLUE, 8);
ct.transitionTo(Color.GREEN, 4);
which would then transition from BLUE to GREEN.
Once all the transition colors are generated you can access them separately:
import java.awt.*;
import javax.swing.*;
import java.util.*;
public class ColorTransition
{
private ArrayList<Color> colors;
public ColorTransition(Color startColor, Color endColor, int steps)
{
colors = new ArrayList<>(steps);
colors.add( startColor );
transitionTo(endColor, steps);
}
public void transitionTo(Color endColor, int steps)
{
Color startColor = colors.get(colors.size() - 1);
float rDelta = endColor.getRed() - startColor.getRed();
float gDelta = endColor.getGreen() - startColor.getGreen();
float bDelta = endColor.getBlue() - startColor.getBlue();
for (int i = 1; i < steps; i++)
{
float stepIncrement = (float)i / (steps - 1);
int rValue = (int)(startColor.getRed() + (rDelta * stepIncrement));
int gValue = (int)(startColor.getGreen() + (gDelta * stepIncrement));
int bValue = (int)(startColor.getBlue() + (bDelta * stepIncrement));
Color color = new Color(rValue, gValue, bValue);
colors.add( color );
}
}
public int size()
{
return colors.size();
}
public Color getColorAt(int index)
{
return colors.get( index );
}
private static void createAndShowGUI()
{
ColorTransition ct = new ColorTransition(Color.RED, Color.BLUE, 8);
// ct.transitionTo(Color.GREEN, 4);
JPanel panel = new JPanel( new GridLayout(0, 1) );
for (int i = 0; i < ct.size(); i++)
{
JTextField textField = new JTextField(25);
textField.setBackground( ct.getColorAt(i) );
panel.add( textField );
}
JFrame frame = new JFrame("Color Transition");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}

Why are JLabels being painted over higher components in a JLayeredPane?

I have a JLayeredPane that has four layers:
JPanel set as a background
Grid of JPanels each holding a JLabel
Grid of JPanels each holding several JLabels that are only set to visible if the label in the panel below is empty
A custom component that is only used to override the paintComponent() method to draw over everything below
For some reason if I change the background colour of the labels in layer 3 and then draw to layer 4, the labels in layer 3 are painted over the graphics painted in level 4. I have tried to set ignoreRepaint() on various components as well as playing around with the opacity and code structure but all to no avail.
Does anyone know how to prevent this from happening?
I won't attach the source code because the project is quite large but I've attached an example that runs as a stand alone program and demonstrates my problem when you hit the "add arrow" button.
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
public class GraphicsTest {
#SuppressWarnings("serial")
class Painter extends JComponent {
public Painter(int x, int y) {
setBounds(0, 0, x, y);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
}
private static final int CELL_SIZE = 40;
private static final int NOTE_SIZE = 20;
private JFrame frame;
private static JButton test;
private static JButton clear;
private static JLayeredPane pane = new JLayeredPane();
private static JPanel back = new JPanel();
private static JPanel[][] cellPanels = new JPanel[10][10];
private static JLabel[][] cells = new JLabel[10][10];
private static JPanel[][] notePanels = new JPanel[10][10];
private static JLabel[][][] notes = new JLabel[10][10][4];
private static Painter painter;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
GraphicsTest window = new GraphicsTest();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public GraphicsTest() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setSize(600, 700);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
pane.setBounds(50, 50, 500, 500);
pane.setLayout(null);
frame.getContentPane().add(pane);
back.setBounds(0, 0, 500, 500);
back.setBackground(Color.BLACK);
pane.add(back, new Integer(100));
for (int i = 0; i < 10; i++) {
for (int k = 0; k < 10; k++) {
String text = "";
if ((i % 2) == 1 && (k % 2) == 1) text = (i + k) + "";
cellPanels[i][k] = new JPanel();
cellPanels[i][k].setBounds(k * CELL_SIZE, i * CELL_SIZE, CELL_SIZE, CELL_SIZE);
cellPanels[i][k].setBackground(Color.WHITE);
cellPanels[i][k].setBorder(new LineBorder(Color.BLACK, 1));
cells[i][k] = new JLabel(text);
cells[i][k].setBounds(0, 0, CELL_SIZE, CELL_SIZE);
cells[i][k].setOpaque(false);
cellPanels[i][k].add(cells[i][k]);
pane.add(cellPanels[i][k], new Integer(200));
}
}
boolean display;
for (int i = 0; i < 10; i++) {
for (int k = 0; k < 10; k++) {
if ((i % 2) == 0 && (k % 2) == 0) {
display = true;
} else {
display = false;
}
notePanels[i][k] = new JPanel();
notePanels[i][k].setBounds(k * CELL_SIZE, i * CELL_SIZE, CELL_SIZE, CELL_SIZE);
notePanels[i][k].setBackground(Color.WHITE);
notePanels[i][k].setBorder(new LineBorder(Color.BLACK, 1));
notePanels[i][k].setLayout(null);
for (int m = 0; m < 2; m++) {
for (int p = 0; p < 2; p++) {
notes[i][k][(m * 2) + p] = new JLabel(30 + "");
notes[i][k][(m * 2) + p].setBounds(m * NOTE_SIZE, p * NOTE_SIZE, NOTE_SIZE, NOTE_SIZE);
notes[i][k][(m * 2) + p].setOpaque(true);
notePanels[i][k].add(notes[i][k][(m * 2) + p]);
}
}
if (display) {
notePanels[i][k].setVisible(true);
} else {
notePanels[i][k].setVisible(false);
}
pane.add(notePanels[i][k], new Integer(300));
}
}
painter = new Painter(500, 500);
pane.add(painter, new Integer(400));
test = new JButton("Add Arrow");
test.setBounds(50, 600, 100, 25);
test.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
highlightNotes();
Arrow.drawArrow(painter.getGraphics(), 20, 20, 400, 400, 20, 30, 40, Color.BLACK, Color.GREEN);
}
});
frame.getContentPane().add(test);
clear = new JButton("Clear");
clear.setBounds(175, 600, 100, 25);
clear.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
painter.repaint();
}
});
frame.getContentPane().add(clear);
}
private static void highlightNotes() {
for (int i = 0; i < 10; i++) {
for (int k = 0; k < 10; k++) {
for (int n = 0; n < 4; n++) {
notes[i][k][n].setBackground(Color.BLUE);
}
}
}
}
static class Arrow {
public static void drawArrow(Graphics g, int tailx, int taily, int headx, int heady,
int shaftw, int headw, int headh, Color outline, Color fill) {
if ((shaftw % 2) == 0) {
shaftw--;
}
if ((headw % 2) == 0) {
headw--;
}
if ((headh % 2) == 0) {
headh--;
}
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
double length = Math.sqrt((double) (((headx - tailx) * (headx - tailx))
+ ((heady - taily) * (heady - taily))));
int tailLength = (int) (length - headw) + 1;
double theta = Math.atan2(heady - taily, headx - tailx);
Point point1 = new Point(0, -(shaftw / 2));
point1 = getTransPoint(point1, theta);
point1.x += tailx;
point1.y += taily;
Point point2 = new Point(tailLength, -(shaftw / 2));
point2 = getTransPoint(point2, theta);
point2.x += tailx;
point2.y += taily;
Point point3 = new Point(tailLength, -(headw / 2));
point3 = getTransPoint(point3, theta);
point3.x += tailx;
point3.y += taily;
Point point4 = new Point((int) length, 0);
point4 = getTransPoint(point4, theta);
point4.x += tailx;
point4.y += taily;
Point point5 = new Point(tailLength, (headw / 2));
point5 = getTransPoint(point5, theta);
point5.x += tailx;
point5.y += taily;
Point point6 = new Point(tailLength, (shaftw / 2));
point6 = getTransPoint(point6, theta);
point6.x += tailx;
point6.y += taily;
Point point7 = new Point(0, (shaftw / 2));
point7 = getTransPoint(point7, theta);
point7.x += tailx;
point7.y += taily;
//Create arrow at tail coordinates passed in
Polygon arrow = new Polygon();
arrow.addPoint(point1.x, point1.y);
arrow.addPoint(point2.x, point2.y);
arrow.addPoint(point3.x, point3.y);
arrow.addPoint(point4.x, point4.y);
arrow.addPoint(point5.x, point5.y);
arrow.addPoint(point6.x, point6.y);
arrow.addPoint(point7.x, point7.y);
//Draw and fill the arrow
g2.setColor(fill);
g2.fillPolygon(arrow);
g2.setColor(outline);
g2.drawPolygon(arrow);
}
private static Point getTransPoint(Point point, double theta) {
int x = (int) ((point.x * Math.cos(theta)) - (point.y * Math.sin(theta)));
int y = (int) ((point.y * Math.cos(theta)) + (point.x * Math.sin(theta)));
return new Point(x, y);
}
}
}

Matrix square brackets

I'm using Java Swing and I need to display a matrix with square brackets (normal square bracket like the one we use in math that spans more than one line), the matrix size is not fixed, it depends on the input.
Here is the code I'm using to display the matrix:
public static void printMatrix(String[][] matrix) {
String output = "";
for (int x = 0; x < matrix.length; x++) {
output += Arrays.toString(matrix[x]) + "\n";
}
JOptionPane.showMessageDialog(null, output, "Matrix",
JOptionPane.INFORMATION_MESSAGE);
}
The output:
But I need to have one big connected square bracket as follows:
So I'm searching on how to do this and I found this link https://docs.oracle.com/javase/tutorial/uiswing/components/border.html but it doesn't contain the brackets that I need and also found this https://team.mumie.net/mumie/mathletfactory_lib_apidocs/net/mumie/mathletfactory/display/noc/matrix/MatrixBorder.html#MatrixBorder%28java.awt.Component,%20int%29 but I didn't find any examples on how to use it.
Based on nIcE cOw's answer on one of my above comments, you need to create your own CustomBorder class that extends AbstractBorder and override its paintBorder() method to draw each part of the brackets.
In this case I divided this task in 3 parts, the top / bottom / left & right part of both brackets.
The internalGap variable is the space that should be between the content and the border
Here are some screenshots of how the output looks like:
With 2, 6 and 10 elements
The code that produces the above outputs is:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Insets;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.AbstractBorder;
public class EquationMatrixBorder {
private JPanel pane;
private CustomBorder customBorder;
private static final int ROWS_AND_COLS = 1;
private void displayGUI() {
JFrame frame = new JFrame("Custom Border Example");
customBorder = new CustomBorder(Color.RED, 15, 10);
pane = new JPanel();
pane.setLayout(new GridLayout(ROWS_AND_COLS, ROWS_AND_COLS, 15, 15));
//Used to fill the grid, not relevant to question
Random random = new Random();
for (int i = 0; i < ROWS_AND_COLS; i++) {
for (int j = 0; j < ROWS_AND_COLS; j++) {
int r = 0;
if (j % 2 == 0) {
r = random.nextInt(2);
} else {
r = random.nextInt(2) - 1;
}
pane.add(new JLabel(String.valueOf(r)));
}
}
pane.setBorder(customBorder);
frame.add(pane);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
#Override
public void run() {
new EquationMatrixBorder().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
class CustomBorder extends AbstractBorder {
private Color color;
private int gap;
private int bracketsTopAndBottom = 10;
private int internalGap;
public CustomBorder(Color color, int gap, int internalGap) {
this.color = color;
this.gap = gap;
this.internalGap = internalGap;
}
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
super.paintBorder(c, g, x, y, width, height);
Graphics2D g2d = null;
if (g instanceof Graphics2D) {
g2d = (Graphics2D) g;
g2d.setColor(color);
g2d.setStroke(new BasicStroke(3));
//top part of brackets
g2d.drawLine(x + gap, y + gap, x + gap + bracketsTopAndBottom, (y + gap));
g2d.drawLine(width - x - gap - bracketsTopAndBottom, y + gap, width - gap - x, (y + gap));
//bottom part of brackets
g2d.drawLine(x + gap, height - gap, x + gap + bracketsTopAndBottom, height - gap);
g2d.drawLine(width - x - gap - bracketsTopAndBottom, height - gap, width - gap - x, height - gap);
//left and right part of brackets
g2d.drawLine(x + gap, y + gap, x + gap, height - gap);
g2d.drawLine(width - x - gap, y + gap, width - x - gap, height - gap);
}
}
#Override
public Insets getBorderInsets(Component c) {
return getBorderInsets(c, new Insets(gap, gap, gap, gap));
}
#Override
public Insets getBorderInsets(Component c, Insets insets) {
insets.left = insets.top = insets.right = insets.bottom = gap + internalGap;
return insets;
}
}
Note
I haven't done rows and cols numbers shown in desired output of OP, I'm leaving that out as this question is only related to the square brackets

Multiple graphic objects from method

I had a task to draw checkers board. Here is my frame class
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JTabbedPane;
public class AppFrame extends JFrame {
public AppFrame() {
setTitle("Kółko i kwadracik");
setSize(1000, 1500);
setLocationRelativeTo(null);
initGUI();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void initGUI() {
setLayout(new BorderLayout());
JTabbedPane tabPane = new JTabbedPane();
tabPane.addTab("Plansza", new PlanszaGry());
tabPane.addTab("Obrazek", new PanelZObrazkiem());
tabPane.addTab("Wykres", new Wykres());
tabPane.addTab("Warcaby", new Warcaby());
tabPane.addTab("4 Warcaby", new Warcaby4());
add(tabPane, BorderLayout.CENTER);
}
}
Than a class to create single checkers board, it's the one new Warcaby()
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.geom.Line2D;
import javax.swing.JPanel;
public class Warcaby extends JPanel {
public void paint(Graphics g) {
super.paint(g);
setBackground(Color.WHITE);
Graphics2D g2 = (Graphics2D) g;
Stroke defaultStroke = g2.getStroke();
int y = 9; // tu ustawiamy liczbę linii (czyli w sumie wilekość planszy)
// linie planszy do gry
for (int i = 0; i <= y; i++) {
float dash[] = { 10.0f };
Stroke lineStroke = new BasicStroke(3.0f, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER);
g2.setStroke(lineStroke);
g2.setColor(Color.BLACK);
int x = i * 100;
g2.draw(new Line2D.Double(100 + x, 100, 100 + x, 100 * y));// linie
// pionowe
g2.draw(new Line2D.Double(100, 100 + x, 100 * y, 100 + x)); // linie
// poziome
}
// Plansza do gry (czarne/białe pola)
for (int a = 1; a < y; a++) {
if (a % 2 != 0) {
for (int b = 1; b < y; b++) {
if (b % 2 == 0) {
g.setColor(Color.black);
g.fillRect(b * 100, a * 100, 100, 100);
}
}
} else {
for (int b = 1; b < y; b++) {
if (b % 2 != 0) {
g.setColor(Color.black);
g.fillRect(b * 100, a * 100, 100, 100);
}
}
}
}
}
}
My next task is to draw 4 boards next to eachother, teacher gave me a hint to create method drawing one board with information about it's position. I can't figure it out how to even start. I've start with this:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.geom.Line2D;
import javax.swing.JPanel;
public class Warcaby4 extends JPanel {
public void Warcaby(Graphics g, int x, int y) {
super.paint(g);
setBackground(Color.WHITE);
Graphics2D g2 = (Graphics2D) g;
Stroke defaultStroke = g2.getStroke();
float dash[] = { 10.0f };
Stroke lineStroke = new BasicStroke(3.0f, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER);
g2.setStroke(lineStroke);
g2.setColor(Color.BLACK);
for (int i = 0; i <= y; i++) {
x = i * 100;
g2.draw(new Line2D.Double(100 + x, 100, 100 + x, 100 * y));// linie
// pionowe
g2.draw(new Line2D.Double(100, 100 + x, 100 * y, 100 + y)); // linie
// poziome
}
// Plansza do gry (czarne/białe pola)
for (int a = 1; a < y; a++) {
if (a % 2 != 0) {
for (int b = 1; b < y; b++) {
if (b % 2 == 0) {
g.setColor(Color.black);
g.fillRect(b * 100, a * 100, 100, 100);
}
}
} else {
for (int b = 1; b < y; b++) {
if (b % 2 != 0) {
g.setColor(Color.black);
g.fillRect(b * 100, a * 100, 100, 100);
}
}
}
}
}
}
Now I don't know where and how call out it 4 times, am I even doing it right? Please give me some suggestions. :)
My next task is to draw 4 boards next to eachother, teacher gave me a hint to create method drawing one board with information about it's position. I can't figure it out how to even start. I've start with this:
Why not just re-use the component you already have? For example, using a GridLayout you could just create as many components as you need...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Insets;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class AppFrame {
public static void main(String[] args) {
new AppFrame();
}
public AppFrame() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(2, 2));
frame.add(new Warcaby());
frame.add(new Warcaby());
frame.add(new Warcaby());
frame.add(new Warcaby());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Warcaby extends JPanel {
public Warcaby() {
setBackground(Color.WHITE);
setBorder(new EmptyBorder(5, 5, 5, 5));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// setBackground(Color.WHITE);
Graphics2D g2 = (Graphics2D) g;
Insets insets = getInsets();
int horontialPadding = insets.left + insets.right;
int verticalPadding = insets.top + insets.bottom;
int width = getWidth() - horontialPadding;
int height = getHeight() - verticalPadding;
int size = Math.min(width, height) / 10;
int xOffset = insets.left + ((width - (size * 10)) / 2);
int yOffset = insets.top + ((height - (size * 10)) / 2);
for (int vertical = 0; vertical < 10; vertical++) {
for (int horzontial = 0; horzontial < 10; horzontial++) {
int x = horzontial * size;
int y = vertical * size;
g2.setColor(Color.WHITE);
if (vertical % 2 == 0) {
if (horzontial % 2 == 0) {
g2.setColor(Color.BLACK);
}
} else if (horzontial % 2 != 0) {
g2.setColor(Color.BLACK);
}
g2.fillRect(xOffset + x, yOffset + y, size, size);
}
}
g2.setColor(Color.BLACK);
g2.drawRect(xOffset, yOffset, size * 10, size * 10);
}
}
}
Sorry, I optimised your drawing code, now it can resize based on the available space.
Also, you should NEVER update the state of the UI from within any paint method (like calling setBackground), this is a very bad idea which could lead into an infinite paint loop which would consume your CPU cycles and render your system unusable (yes, I've done this)
As a general rule of thumb, you should prefer paintComponent over paint. See Painting in AWT and Swing and Performing Custom Painting for more details
I've managed to finish this task on my own. Here's the code in case someone will have similar problem.
public void paint(Graphics g) {
super.paint(g);
rysujWarcaby((Graphics) g, 50, 50);
rysujWarcaby((Graphics) g, 50, 500);
rysujWarcaby((Graphics) g, 500, 50);
rysujWarcaby((Graphics) g, 500, 500);
}
public void rysujWarcaby(Graphics g, int x, int y) {
int xx = 1;
int nr = 9;
setBackground(Color.YELLOW);
Graphics2D g2 = (Graphics2D) g;
Stroke lineStroke = new BasicStroke(3.0f, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER);
g2.setStroke(lineStroke);
g2.setColor(Color.BLACK);
for (int i = 0; i < nr; i++) {
xx = i * 50;
g2.draw(new Line2D.Double(x + xx, y, xx + x, y + 50 * 8));
g2.draw(new Line2D.Double(x, y + xx, x + 50 * 8, y + xx));
}
}

Need to add Scroll Bar

I am an enthusiast rather than a programmer. I have thousands of pdf files to go through and extract some data. The data is in X inside boxes (I suspect a graphic within the pdf) there is no evidence of this data if I convert the PDF to text so...
I am converting the PDF to image then looking at the image in certain areas where I expect the X to be and counting black pixels, so far so good.
The PDF does not fit in the window height-wise so I need to add a scrollbar.
I don't understand how I can add a scrollbar to the main window.
Can someone just steer me in the right direction
Thank you
The code is incomplete but working:
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
public class ImageViewer {
public static void main(String[] args){
EventQueue.invokeLater(new Runnable()
{
public void run(){
ImageFrame frame = new ImageFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
);
}
}
class ImageFrame extends JFrame{
/**
*
*/
private static final long serialVersionUID = 1L;
public ImageFrame(){
setTitle("Image Viewer");
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
ImageComponent component = new ImageComponent();
add(component);
}
public static final int DEFAULT_WIDTH = 860;
public static final int DEFAULT_HEIGHT = 1000;
}
class ImageComponent extends JComponent{
/**
*
*/
private static final long serialVersionUID = 1L;
private Image image;
public ImageComponent(){
try{
File image2 = new File("Files/4.jpg");
image = ImageIO.read(image2);
}
catch (IOException e){
e.printStackTrace();
}
}
public void paintComponent (Graphics g){
if(image == null) return;
int imageWidth = image.getWidth(this);
int imageHeight = image.getHeight(this);
g.drawImage(image, 0, 0, this);
// Draw on the BufferedImage via the graphics context.
g.setColor(Color.RED);
g.drawRect(445, 153, 20, 20);
g.drawRect(552, 153, 20, 20);
g.drawRect(661, 153, 20, 20);
g.drawRect(445, 182, 20, 20);
g.drawRect(552, 182, 20, 20);
g.drawRect(661, 182, 20, 20);
g.drawRect(445, 226, 20, 20);
g.drawRect(552, 226, 20, 20);
g.drawRect(661, 226, 20, 20);
g.drawRect(445, 271, 20, 20);
g.drawRect(552, 271, 20, 20);
g.drawRect(661, 271, 20, 20);
for (int i = 0; i*imageWidth <= getWidth(); i++)
for(int j = 0; j*imageHeight <= getHeight();j++)
if(i+j>0) g.copyArea(0, 0, imageWidth, imageHeight, i*imageWidth, j*imageHeight);
//Count black pixels to see if the box contains an X
int A1 = 0;
for (int y = 153; y < 173; y++)
{
for (int x = 445; x < 465; x++)
{
int c = ((BufferedImage) image).getRGB(x,y);
Color color = new Color(c);
if (c != -1)
{
A1++;
}
}
}
System.out.println("First box pixel count = " + A1);
//Count black pixels to see if the box contains an X
int A2 = 0;
for (int y = 153; y < 173; y++)
{
for (int x = 552; x < 572; x++)
{
int c = ((BufferedImage) image).getRGB(x,y);
if (c != -1)
{
A2++;
}
}
}
System.out.println("Second box pixel count = " + A2);
//Count black pixels to see if the box contains an X
int A3 = 0;
for (int y = 153; y < 173; y++)
{
for (int x = 661; x < 681; x++)
{
int c = ((BufferedImage) image).getRGB(x,y);
if (c != -1)
{
A3++;
}
}
}
System.out.println("Third box pixel count = " + A3);
}
}
Look for something like JScrollPane myPane = new JScrollPane();

Categories