Related
I am display an image on JPanel and on that image i am creating a Grid of 8*8 by setStroke of Graphics2D. Now when i zooming that grid lines by setting setStroke it does not work for all images. I am thinking that this problem is associated with resolution of images. How can i solve this problem
BufferedImage bi; //loading buffered image some how
JCombobox jComboBox; //creating combobox having different zoom factor
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
int gridLinesThikness = (int) ((float) jComboBox.getSelectedIndex() * (float) (bi.getWidth() / (float) screen.width));
if (gridLinesThikness < 1)
gridLinesThikness = 1;
g2.setStroke(new BasicStroke(gridLinesThikness));
Try this code:
package sad;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class zoom extends javax.swing.JPanel {
private static int prevN = 0;
private Dimension preferredSize = new Dimension(400,400);
private Rectangle2D[] rects = new Rectangle2D[50];
public static void main(String[] args) {
JFrame jf = new JFrame("test");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setSize(800, 800);
JPanel containerPanel = new JPanel(); // extra JPanel
containerPanel.setLayout(new GridBagLayout());
containerPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(1, 0, 1)));
zoom zoomPanel = new zoom();
containerPanel.add(zoomPanel);
zoomPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
jf.add(new JScrollPane(containerPanel));
jf.setVisible(true);
}
public zoom() {
// generate rectangles with pseudo-random coords
for (int i=0; i<rects.length; i++) {
rects[i] = new Rectangle2D.Double(
Math.random()*.8, Math.random()*.8,
Math.random()*.2, Math.random()*.2);
}
addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
updatePreferredSize(e.getWheelRotation(), e.getPoint());
}
});
}
private void updatePreferredSize(int n, Point p) {
if(n == 0) // ideally getWheelRotation() should never return 0.
n = -1 * prevN; // but sometimes it returns 0 during changing of zoom
// direction. so if we get 0 just reverse the direction.
double d = (double) n * 1.08;
d = (n > 0) ? 1 / d : -d;
int w = (int) (getWidth() * d);
int h = (int) (getHeight() * d);
preferredSize.setSize(w, h);
int offX = (int)(p.x * d) - p.x;
int offY = (int)(p.y * d) - p.y;
getParent().setLocation(getParent().getLocation().x-offX,getParent().getLocation().y-offY);
//in the original code, zoomPanel is being shifted. here we are shifting containerPanel
getParent().doLayout(); // do the layout for containerPanel
getParent().getParent().doLayout(); // do the layout for jf (JFrame)
prevN = n;
}
#Override
public Dimension getPreferredSize() {
return preferredSize;
}
private Rectangle2D r = new Rectangle2D.Float();
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.red);
int w = getWidth();
int h = getHeight();
for (Rectangle2D rect : rects) {
r.setRect(rect.getX() * w, rect.getY() * h,
rect.getWidth() * w, rect.getHeight() * h);
((Graphics2D)g).draw(r);
}
}
}
You may not be able to tell that much but for some reason a few of the characters are being offset somehow, due to a flaw in my algorithm...If someone could figure out what is causing it, I would really appreciate it and any critique is welcome as I'm still very new at java.
Edit: If you look at the image above it's the E that is offset in WE on the left and right side
Edit: I think it may be in my calculation of the size of text vs size of circle
Edit: Ok so when I enter 600 for width and height everything seems to fall in place, but as it gets smaller from say 250 for example the characters start becoming more offset and overlapping
Main class:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
/**
* Created by John on 7/11/2014.
*/
public class Prog14_05 extends Application {
#Override
public void start(Stage primaryStage) {
// Create Pane
circularText phrase = new circularText("WE ARE ANONYMOUS, " +
"WE ARE LEGION, WE DO NOT FORGIVE, WE DO NOT FORGET ",
480, 480);
// Place clock and label in border pane
GridPane pane = new GridPane();
pane.setPadding(new Insets(phrase.getTextSize() * 2));
pane.setAlignment(Pos.CENTER);
pane.setStyle("-fx-background-color: black");
pane.getChildren().add(phrase);
// Create a scene and place it in the stage
Scene scene = new Scene(pane);
primaryStage.setTitle("Exercise14_05");
primaryStage.setScene(scene);
primaryStage.show();
}
}
circularText Class:
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
/**
* Created by John on 7/11/2014.
*/
public class circularText extends Pane {
double textSize = 30;
String string = "";
String fontName = "";
Font font;
// Pane's width and height
private double w = 250, h = 250;
/** Create Constructor */
public circularText (String phrase, double w, double h) {
this.w = w;
this.h = h;
this.string = phrase;
textSize = (this.w / this.string.length()) * 2;
Font font = new Font("Times Roman", textSize);
paintText(this.string, this.font);
}
/** Set new font */
public void setFont(String name) {
Font font = new Font(name, textSize);
this.font = font;
this.fontName = name;
paintText(this.string, this.font);
}
/** Return textSize */
public double getTextSize() {
return this.textSize;
}
/** Set textSize */
public void setTextSize(double textSize) {
this.textSize = textSize;
Font font = new Font(fontName, textSize);
this.font = font;
paintText(this.string, this.font);
}
/** Return pane's width */
public double getW() {
return w;
}
/** Set pane's width */
public void setW(double w) {
this.w = w;
textSize = (this.w / this.string.length()) * 2;
paintText(this.string, this.font);
}
/** Return pane's height */
public double getH() {
return h;
}
/** Set pane's height */
public void setH(double h) {
this.h = h;
textSize = (this.w / this.string.length()) * 2;
paintText(this.string, this.font);
}
/** Paint the Letters */
protected void paintText(String phrase, Font font) {
// Initialize parameters
double radius = Math.min(w, h) * 0.8 * 0.5;
double centerX = w / 2;
double centerY = h / 2;
double size = radius / 4 - this.getTextSize();
// Draw circle
Circle circle = new Circle(centerX - size - textSize, centerY - size,
radius);
circle.setFill(null);
circle.setStroke(null);
getChildren().clear();
getChildren().add(circle);
// Place text in a circular pattern
int i = 0;
double degree = 360 / phrase.length();
for (double degrees = 0; i < phrase.length(); i++, degrees += degree) {
double pointX = circle.getCenterX() + circle.getRadius() *
Math.cos(Math.toRadians(degrees));
double pointY = circle.getCenterY() + circle.getRadius() *
Math.sin(Math.toRadians(degrees));
Text letter = new Text(pointX, pointY, phrase.charAt(i) + "");
letter.setFont(font);
letter.setFill(Color.LIME);
letter.setRotate(degrees + 90);
getChildren().add(letter);
}
}
}
My trig isn't very good so I can't help you there. I'm thinking the "W" may be offset, not the "E". I know in other versions of Swing the "W" has caused painting problems before, but I don't remember the details. So I might suggest trying different characters to see if you still have the same problem at those two locations.
Here is another example of circular painting that I found on the web a long time ago. I tried your text and the "WE" is overlapped. I changed the "W" to an "R" and it seems to work ok, so maybe this validates my above statement?
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Font;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GradientPaint;
import java.awt.RenderingHints;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.geom.AffineTransform;
//import com.sun.awt.AWTUtilities;
public class SplashPortalPanel6 extends JPanel
{
private static final long serialVersionUID = 1L;
// private static final char[] MESSAGE = " SplashPortal.net".toCharArray();
private static final char[] MESSAGE = " WE ARE ANONYMOUS, WE ARE LEGION, WE DO NOT FORGIVE, WE DO NOT FORGET ".toCharArray();
// private static final char[] MESSAGE = " RE ARE ANONYMOUS, RE ARE LEGION, RE DO NOT FORGIVE, RE DO NOT FORGET ".toCharArray();
private static final double R90 = Math.toRadians(90);
private static final double R_90 = Math.toRadians(-90);
private AffineTransform cumalativeRotation = new AffineTransform();
private double rotation = Math.toRadians(360.0 / MESSAGE.length);
private Font font = new Font("Impact",Font.ITALIC,40);
private final Timer timer = new Timer(1000/76, new ActionListener() {
public void actionPerformed(ActionEvent e) {
repaint();//just repaint
}
});
public SplashPortalPanel6() {
setPreferredSize(new java.awt.Dimension(600, 600));
setOpaque(false);
}
//This method is called when the panel is connected to a native
//screen resource. It's an indication we can now start painting.
public void addNotify() {
super.addNotify();
timer.start();
}
public void removeNotify() {
super.removeNotify();
timer.stop();
}
private static final GradientPaint gradient = new GradientPaint(0F, 0F, Color.BLUE, 5F, 10F, Color.CYAN, true);
private static final int x = 0, y = 0, w = 100, h = 100;
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.setFont(font);
g2.translate( getWidth()/2, getHeight()/2 );
cumalativeRotation.rotate(rotation/50);
g2.transform( cumalativeRotation );
for(int i = 0; i < MESSAGE.length; i++) {
// fill the rectangle
g2.translate(250, 0);
g2.rotate(R90);
g2.setColor(Color.BLACK);
// g2.fillRect(x,y,w,h);
// draw the border
g2.setColor(Color.WHITE);
// g2.drawRect(x,y,w,h);
// draw the character
g2.setPaint(gradient);
g2.drawChars(MESSAGE,i, 1, x+30, y+50);
g2.rotate(R_90);
g2.translate(-250, 0);
g2.rotate(rotation);
}
}
public static void createAndShowSplashScreen() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setUndecorated(true);
frame.setContentPane(new SplashPortalPanel6());
frame.pack();
frame.setLocationRelativeTo(null);
// AWTUtilities.setWindowOpaque(frame, false);
//frame.setAlwaysOnTop(true);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowSplashScreen();
}
});
}
}
Note, if you uncomment the "fillRect" and "drawRect" statements you will see the original implementation of the code. Of course you will need to use the shorter first message string to see the effect.
Add
letter.setTextAlignment(TextAlignment.CENTER);
letter.setWrappingWidth(100);
Not sure what is going on with JavaFX Text rendering.
The math appears correct. For clarity when coding some suggest adding explicit typing to ensure your not mixing doubles with floats with ints. So instead of
double centerY = h / 2;
do
double centerY = h / 2.0d;
(Also take out extra "this." clutter, many methods are not being used like "setH", and make class name upper case CircularText)
Alright here is what I got so far, let me know what you all think and what can be improved upon...
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
/**
* Created by John on 7/11/2014.
*/
public class CircularText extends Pane {
private double circleWidth;
private double circleHeight;
private double textSize;
private double textStartDegree;
private double textRotate;
private double gapSpacing;
private double offSetX;
private double offSetY;
private Font font;
private Paint textFill;
private String fontName;
final String text;
/** Default Constructor */
public CircularText(String text) {
this.circleWidth = 250;
this.circleHeight = 250;
this.text = text;
textSize = (this.circleWidth / this.text.length()) * 2;
this.font = new Font("Times Roman", textSize);
this.textFill = Color.BLACK;
this.textStartDegree = 240;
this.textRotate = 90;
this.gapSpacing = 0.975;
this.offSetX = 4;
this.offSetY = 3;
paintText(this.text, this.font);
}
/** Create Constructor */
public CircularText (String text, double w, double h) {
this.circleWidth = w;
this.circleHeight = h;
this.text = text;
textSize = (this.circleWidth / (this.text.length()) * 2);
this.font = new Font("Times Roman", textSize);
this.textFill = Color.BLACK;
this.textStartDegree = 240;
this.textRotate = 90;
this.gapSpacing = 0.975;
this.offSetX = 4;
this.offSetY = 3;
paintText(this.text, this.font);
}
/** Get font color */
public Paint getTextFill() {
return textFill;
}
/** Set font color */
public void setTextFill(Paint textFill) {
this.textFill = textFill;
this.font = new Font(fontName, textSize);
paintText(this.text, this.font);
}
/** Get starting position for text */
public double getTextStartDegree() {
return textStartDegree;
}
/** Set starting position for text */
public void setTextStartDegree(double textStartDegree) {
this.textStartDegree = textStartDegree;
this.font = new Font(fontName, textSize);
paintText(this.text, this.font);
}
/** Get letter rotation */
public double getTextRotate() {
return textRotate;
}
/** Set letter rotation */
public void setTextRotate(double textRotate) {
this.textRotate = textRotate;
this.font = new Font(fontName, textSize);
paintText(this.text, this.font);
}
/** Get spacing between ending and beginning of phrase */
public double getGapSpacing() {
return gapSpacing;
}
/** Set spacing between ending and beginning of phrase */
public void setGapSpacing(double gapSpacing) {
this.gapSpacing = gapSpacing;
this.font = new Font(fontName, textSize);
paintText(this.text, this.font);
}
/** Get current font */
public Font getFont() {
return this.font;
}
/** Set new font */
public void setFont(String name) {
this.font = new Font(name, textSize);
this.fontName = name;
paintText(this.text, this.font);
}
/** Return textSize */
public double getTextSize() {
return this.textSize;
}
/** Set textSize */
public void setTextSize(double textSize, double offSetX, double offSetY) {
this.textSize = textSize;
this.offSetX = offSetX;
this.offSetY = offSetY;
this.font = new Font(fontName, textSize);
paintText(this.text, this.font);
}
/** Return circle's width */
public double getCircleWidth() {
return circleWidth;
}
/** Set circle's width */
public void setCircleWidth(double w) {
this.circleWidth = w;
textSize = (this.circleWidth / this.text.length()) * 2;
paintText(this.text, this.font);
}
/** Return circle's height */
public double getCircleHeight() {
return circleHeight;
}
/** Set circle's height */
public void setCircleHeight(double h) {
this.circleHeight = h;
textSize = (this.circleWidth / this.text.length()) * 2;
paintText(this.text, this.font);
}
/** Paint the Letters */
protected void paintText(String text, Font font) {
getChildren().clear();
// Initialize parameters
double radius = Math.min(circleWidth, circleHeight) * 0.8 * 0.5;
double centerX = circleWidth / 2;
double centerY = circleHeight / 2;
// Place text in a circular pattern
int i = 0;
double degree = 360.0 / (text.length() / this.gapSpacing);
for (double degrees = this.textStartDegree;
i < text.length(); i++, degrees += degree) {
double pointX = centerX + radius *
Math.cos(Math.toRadians(degrees)) - (this.textSize) *
this.offSetX;
double pointY = centerY + radius *
Math.sin(Math.toRadians(degrees)) - (this.textSize) *
this.offSetY;
Text letter = new Text(pointX, pointY,
String.valueOf(text.charAt(i)));
letter.setFont(font);
letter.setFill(this.textFill);
letter.setRotate(degrees + this.textRotate);
letter.setTextAlignment(TextAlignment.CENTER);
getChildren().add(letter);
}
}
}
After testing this with Courier New font, it appears to render flawlessly. I also tested this with other fonts and everything still rendered correctly. It appears the flaw in my code was correlated with the Circle object I had created for troubleshooting and for some reason decided to use in my algorithm. After removing this Circle object and fixing small flaws in my code and adding flexibility, everything works perfectly :)
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
/**
* Created by John on 7/11/2014.
*/
public class Prog14_05 extends Application {
#Override
public void start(Stage primaryStage) {
// Create Pane
CircularText phrase = new CircularText("TESTING MY CIRCULAR" +
"TEXT OBJECT CLASS",
500, 500);
phrase.setFont("Courier New");
phrase.setTextFill(Color.LIME);
phrase.setTextSize(20);
// Place clock and label in border pane
GridPane pane = new GridPane();
pane.setPadding(new Insets(phrase.getTextSize()));
pane.setAlignment(Pos.CENTER);
pane.setStyle("-fx-background-color: black");
pane.getChildren().add(phrase);
// Create a scene and place it in the stage
Scene scene = new Scene(pane);
primaryStage.setTitle("Exercise14_05");
primaryStage.setScene(scene);
primaryStage.show();
}
}
P.S Test my code and let me know if you find any bugs, Thanks for everyone's help
I am making a button where when you click on it it changes the text. But when I click on the button and change the text, the button does not change size according to the text. Instead, it gets smaller and attempts to make that "..." thing when it does not have enough room. Here is my code:
Text.java
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args){
JFrame frame = new JFrame();
JPanel panel = new JPanel();
frame.add(panel);
final CButton button = new CButton("");
panel.add(button);
button.addMouseListener(new MouseListener(){
#Override
public void mouseClicked(MouseEvent arg0) {
button.setText(button.getText()+"f");
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
});
frame.setSize(500,500);
frame.setVisible(true);
}
}
CButton.java
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Area;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JButton;
import javax.swing.JOptionPane;
public class CButton extends JButton implements ComponentListener, KeyListener {
protected static final int BORDER_WIDTH = 5;
private static final Font font = new Font("Arial", Font.PLAIN, 30);
private static final Insets INSETS_MARGIN = new Insets(2, 5, 2, 5);
private static final long serialVersionUID = 1L;
protected Area m_areaDraw = null;
private Area m_areaFill = null;
private double m_dHeightDraw = 0d;
private double m_dHeightFill = 0d;
private double m_dWidthDraw = 0d;
private double m_dWidthFill = 0d;
private int m_nMinHeight = 0;
private int m_nMinWidth = 0;
private int m_nStringHeightMax = 0;
private int m_nStringWidthMax = 0;
private RoundRectangle2D m_rrect2dDraw = null;
private RoundRectangle2D m_rrect2dFill = null;
private Shape m_shape = null;
public CButton(String strLabel) {
super(strLabel);
setContentAreaFilled(false);
setMargin(CButton.INSETS_MARGIN);
setFocusPainted(false);
addComponentListener(this);
addKeyListener(this);
// Determine the buttons initial size
setFont(CButton.font);
Frame frame = JOptionPane.getRootFrame();
FontMetrics fm = frame.getFontMetrics(getFont());
m_nStringWidthMax = fm.stringWidth(getText());
m_nStringWidthMax = Math.max(m_nStringWidthMax,
fm.stringWidth(getText()));
// WARNING: use getMargin. it refers to dist btwn text and border.
// Also use getInsets. it refers to the width of the border
int nWidth = Math.max(m_nMinWidth, m_nStringWidthMax + getMargin().left
+ this.getInsets().left + getMargin().right
+ this.getInsets().right);
m_nStringHeightMax = fm.getHeight();
// WARNING: use getMargin. it refers to dist btwn text and border.
// Also use getInsets. it refers to the width of the border
int nHeight = Math.max(m_nMinHeight, m_nStringHeightMax
+ getMargin().left + this.getInsets().left + getMargin().right
+ this.getInsets().right);
setPreferredSize(new Dimension(
nWidth + ((2 * getFont().getSize()) / 5), nHeight
+ ((2 * getFont().getSize()) / 5)));
// Set the initial draw and fill dimensions
setShape();
}
#Override
public void componentHidden(ComponentEvent e) {
}
#Override
public void componentMoved(ComponentEvent e) {
}
// Needed if we want this button to resize
#Override
public void componentResized(ComponentEvent e) {
m_shape = new Rectangle2D.Float(0, 0, getBounds().width,
getBounds().height);
m_dWidthFill = (double) getBounds().width - 1;
m_dHeightFill = (double) getBounds().height - 1;
m_dWidthDraw = ((double) getBounds().width - 1)
- (CButton.BORDER_WIDTH - 1);
m_dHeightDraw = ((double) getBounds().height - 1)
- (CButton.BORDER_WIDTH - 1);
setShape();
repaint();
}
#Override
public void componentShown(ComponentEvent e) {
}
#Override
public boolean contains(int nX, int nY) {
if ((null == m_shape) || m_shape.getBounds().equals(getBounds())) {
m_shape = new Rectangle2D.Float(0, 0, this.getBounds().width,
this.getBounds().height);
}
return m_shape.contains(nX, nY);
}
// This is so the button is triggered when it has focus
// and we press the Enter key.
#Override
public void keyPressed(KeyEvent e) {
if ((e.getSource() == this) && (e.getKeyCode() == KeyEvent.VK_ENTER)) {
doClick();
}
};
#Override
public void keyReleased(KeyEvent e) {
};
#Override
public void keyTyped(KeyEvent e) {
};
#Override
public void paintBorder(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHints(hints);
g2.setColor(Color.black);
Stroke strokeOld = g2.getStroke();
g2.setStroke(new BasicStroke(CButton.BORDER_WIDTH,
BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.draw(m_areaDraw);
if (getModel().isRollover()) {
g2.setColor(Color.GRAY);
g2.draw(m_areaDraw);
}
g2.setStroke(strokeOld);
};
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHints(hints);
if (getModel().isArmed()) {
g2.setColor(Color.CYAN.darker());
} else {
g2.setColor(Color.CYAN);
}
g2.fill(m_areaFill);
super.paintComponent(g2);
}
private void setShape() {
// Area
double dArcLengthFill = Math.min(m_dWidthFill, m_dHeightFill);
m_rrect2dFill = new RoundRectangle2D.Double(0d, 0d, m_dWidthFill,
m_dHeightFill, dArcLengthFill, dArcLengthFill);
// WARNING: arclength and archeight are divided by 2
// when they get into the roundedrectangle shape
m_areaFill = new Area(m_rrect2dFill);
// Border
double dArcLengthDraw = Math.min(m_dWidthDraw, m_dHeightDraw);
m_rrect2dDraw = new RoundRectangle2D.Double(
(CButton.BORDER_WIDTH - 1) / 2, (CButton.BORDER_WIDTH - 1) / 2,
m_dWidthDraw, m_dHeightDraw, dArcLengthDraw, dArcLengthDraw);
m_areaDraw = new Area(m_rrect2dDraw);
}
#Override
public void setText(String strText) {
super.setText(strText);
int nWidth = Math.max(m_nMinWidth, m_nStringWidthMax + getInsets().left
+ getInsets().right);
int nHeight = Math.max(0, getPreferredSize().height);
setPreferredSize(new Dimension(nWidth, nHeight));
m_dWidthFill = getBounds().width - 1;
m_dHeightFill = getBounds().height - 1;
if ((m_dWidthFill <= 0) || (m_dHeightFill <= 0)) {
m_dWidthFill = (double) getPreferredSize().width - 1;
m_dHeightFill = (double) getPreferredSize().height - 1;
}
m_dWidthDraw = m_dWidthFill - (CButton.BORDER_WIDTH - 1);
m_dHeightDraw = m_dHeightFill - (CButton.BORDER_WIDTH - 1);
setShape();
}
}
You call
setPreferredSize(new Dimension(
nWidth + ((2 * getFont().getSize()) / 5), nHeight
+ ((2 * getFont().getSize()) / 5)));
in the constructor, but never change it. This means that each time the layout manager asks the component what size it would like to be, it always gets the same value.
A preferred solution would be to override getPreferredSize and calculate the size there, if it's not to complicated or time consuming
The next question is why are you going to all this extra effort. Basically, you should simply allow the parent JButton to provide its preferred size and add your requirements around it, or simply use the margins properties or even a Border
You're KeyListener also seems useless as this is the default behaviour of the button anyway and in any case, key bindings would be a preferred solution
My first thought was that it had to do with your humongous CButton implementation. At least, copy/paste of your code created a working application. That's a big plus in my book.
When I simply replaced the strange nWidth calculation in the setText() method with:
int nWidth = 100;
The size was increased after a click and showed an "f", which I assume is what you wanted.
So, I can't really say how to calculate the width, but at least you know where to look and which line to change.
Object fileButton = null;
if("Analyze Text File".equals(command)) {
JFileChooser filechooser;
JFileChooser chooser = new JFileChooser();
int returnVal = filechooser.showOpenDialog(getParent());
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = filechooser.getSelectedFile();
String Stext = (String) readFileAsString(file); //String text = textInput.getText();
Map<Integer, Integer> counts = getCounts(text);
int width = counts.size() * BAR_WIDTH;
int max = maxCount(counts);
int height = max * INCREMENT + 100;
int horizon = height - 25;
HistogramPanel panel = new HistogramPanel(width, counts, height, horizon);
//panel.setBorder(new LineBorder(Color.BLACK, 2));
JOptionPane.showMessageDialog(null, panel);
i am creating a java applet where it counts the frequency/occurence of X words, i have worked out how to do the array to work out the frequency depending on what the user inputs, i need to now create a bar chart that adapts to whatever the user inputs, i have wrote up a code for my bar chart but i dont know how to connect it to my array code.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.net.URL;
import java.io.*;
import java.util.HashMap;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.Map;
import javax.swing.SwingUtilities;
import javax.swing.JOptionPane;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class assignment_work extends JApplet implements ActionListener {
JTextArea textInput; // User Input.
JLabel wordCountLabel; // To display number of words.
JLabel meanLabel; // To display the mean.
public void init() {
// This code from here is the customisation of the Applet, this includes background colour, text colour, text back ground colour, labels and buttons
setBackground(Color.black);
getContentPane().setBackground(Color.black);
textInput = new JTextArea();
textInput.setWrapStyleWord(true);
JPanel ui = new JPanel();
ui.setLayout(Layout(-1));
/* Creating Analyze and Reset buttons */
JButton chartButton = new JButton("Bar Chart");
chartButton.addActionListener(this);
ui.add(chartButton);
JPanel panel = new JPanel(new BorderLayout())
//panel.add(chartButton, BorderLayout.SOUTH);
/* Labels telling the user what to do or what the program is outputting */
wordCountLabel.setBackground(Color.black);
wordCountLabel.setForeground(Color.red);
wordCountLabel.setOpaque(true);
meanLabel.setBackground(Color.white);
meanLabel.setForeground(Color.black);
meanLabel.setOpaque(true);
watermark.setLayout(new BorderLayout());
watermark.setBackground(Color.darkGray);
/* Border for Applet. */
getContentPane().setLayout( new BorderLayout());
getContentPane().add(ui, BorderLayout.CENTER);
/* Scroll bar for the text area where the user will input the text they wish to analyse. */
JScrollPane scroller = new JScrollPane( textInput );
getContentPane().add(scroller, BorderLayout.CENTER);
getContentPane().add(ui, BorderLayout.NORTH);
}
class CustomCanvas extends Canvas {
public CustomCanvas() {
setBackground(Color.darkGray);
setPreferredSize(new Dimension(100, 100));
}
public void paint(Graphics g) {
int x [] = {20,20,10,10,40,40,30,30};
int y [] = {40,20,20,10,10,20,20,40};
int n = 8;
g.setColor(Color.black);
g.fillPolygon(x,y,n);
int wpoint [] = {45,65,85,75,70,60,55};
int zpoint [] = {40,10,40,40,30,30,40};
int npoint = 7;
g.setColor(Color.black);
g.fillPolygon(wpoint,zpoint,npoint);
int a [] = {60,65,70};
int b [] = {25,20,25};
int npoints = 3;
g.setColor(Color.darkGray);
g.fillPolygon(a,b,npoints);
}
}
private int maxCount(Map<Integer, Integer> counts) {
counts.values()) {
if (num > max) {
max = num;
}
}
return max;
}
public class Panel extends JPanel {
int width;
Map<Integer> count;
public Histogram(int width, Map<Integer, Integer> counts, int horizon) {
this.width = width;
this.dimHeight = dimHeight;
this.horizon = horizon;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = 10;
for (Map.Entry<Int> entry : counts.entrySet()) {
int height = entry.getValue() * INCREMENT;
int y = horizon - height;
g.drawString(entry.getValue() + " Frequency", x, y -2);
x += BAR_WIDTH;
}
}
public Dimension getPreferredSize() {
return new Dimension(width, dimHeight);
}
}
public static Map<Int> getCounts(String Input) {
Map<Integer> map = new HashMap<Int>();
String[] array = Input.split("[\\s.,;:!?()");
for (String array) {
Int size;
if (!map(size)) {
map.put(size, 1);
} else {
map.put(map.get(size) + 1);
}
}
return;
}
// Text analysis end
public void actionPerformed(java.awt.event.ActionEvent e) {
if (command.equals("commands")) {
{
final graph<Int> Lengths = new graph<Int>();
String array = Input.Text().split(");
for (int i = 10; i < array.length; i) {
final int Length = array[0].length();
if( Length.Set().container(Length ) ) {
Integer currentNumberOfOccurences = wordLengths.get(wordLength);
currentNumberOfOccurences;
wordLengths.put(wordLength, currentNumberOfOccurences);
}
wordLengths.put(wordLength, 1);
}
double total =10;
double total = 10;
for (final Int length : Lengths.Set()) {
final Int occurrences = Lengths.get(length);
Length = tLength + (length * occurrencers );
totalOccurrences += occurrences;
}
final mean = aLength / lOccurrences;
aLabel.Text("mean word length is: " + (eLength / wOccurrences) );
// System.out.println("mean word length is: " + (total / length) );
}
String array = textInput.getText().split(" ");
int maxWordLength = 0;
wordLength = array[i].length();
if (wordLength > maxWordLength) {
maxWordLength = wordLength;
}
int[] intArray = new int[maxWordLength + 1];
for (int i = 0; i < array.length; i++) {
intArray[array[i].length()]++;
}
for (int i = 1; i < intArray.length; i++) {
out.printf("%d word(s) of length %d<br>", intArray[i], i)
}
else if (command.equals("Reset")) {
textInput.setText("");
textInput.requestFocus();
}
Object chartButton = null;
if (e.getSource() == chartButton) {
String text = textInput.getText();
HistogramPanel panel = new HistogramPanel(width, counts, height, horizon);
//panel.setBorder(new LineBorder(Color.BLACK, 2));
JOptionPane.showMessageDialog(null, panel);
}
};
}
Update
Using JFileCHooser
private String readFileAsString(String filePath) throws IOException {
StringBuffer fileData = new StringBuffer();
BufferedReader reader = new BufferedReader(
new FileReader(filePath));
char[] buf = new char[1024];
int numRead=0;
while((numRead=reader.read(buf)) != -1){
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
}
reader.close();
return fileData.toString();
}
Here's what you want to do to create the dynamic size from the input.
You need to get the number of entries in the map, then multiply it by whatever you want the width of each bar to be.
You need to get the highest value in the map and multiply that by you increment (to draw) amount and create the height from that.
You create a new JPanel with dimension based on the height and width from the previous two points.
Iterate through the map the draw the bars.
I do the things above in the actionPerformed of a button and I add the JPanel to a JOptionPane. Let me know if you need clarification on anything.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class Histogram {
private static final int BAR_WIDTH = 50;
private static final int INCREMENT = 10;
public Histogram() {
final JTextArea textArea = new JTextArea(5, 40);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
JButton go = new JButton("Histogram-me!");
JPanel panel = new JPanel(new BorderLayout());
panel.add(textArea, BorderLayout.CENTER);
panel.add(go, BorderLayout.SOUTH);
JFrame frame = new JFrame();
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
go.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String text = textArea.getText();
Map<Integer, Integer> counts = getCounts(text);
int width = counts.size() * BAR_WIDTH;
int max = maxCount(counts);
int height = max * INCREMENT + 100;
int horizon = height - 25;
HistogramPanel panel = new HistogramPanel(width, counts, height, horizon);
//panel.setBorder(new LineBorder(Color.BLACK, 2));
JOptionPane.showMessageDialog(null, panel);
}
});
}
private int maxCount(Map<Integer, Integer> counts) {
int max = 0;
for (Integer num : counts.values()) {
if (num > max) {
max = num;
}
}
return max;
}
public class HistogramPanel extends JPanel {
int width;
int dimHeight;
int horizon;
Map<Integer, Integer> counts;
public HistogramPanel(int width, Map<Integer, Integer> counts, int dimHeight, int horizon) {
this.width = width;
this.counts = counts;
this.dimHeight = dimHeight;
this.horizon = horizon;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = 10;
for (Map.Entry<Integer, Integer> entry : counts.entrySet()) {
int height = entry.getValue() * INCREMENT;
int y = horizon - height;
g.fillRect(x, y, BAR_WIDTH - 10, height);
g.drawString(entry.getKey() + " chars", x, horizon + 10);
g.drawString(entry.getValue() + " times", x, y -2);
x += BAR_WIDTH;
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, dimHeight);
}
}
public static Map<Integer, Integer> getCounts(String input) {
Map<Integer, Integer> map = new HashMap<>();
String[] array = input.split("[\\s.,;:!?(){}]+");
for (String s : array) {
Integer size = s.length();
if (!map.containsKey(size)) {
map.put(size, 1);
} else {
map.put(size, map.get(size) + 1);
}
}
return map;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Histogram histogram = new Histogram();
}
});
}
}
I am currently trying to paint a Waveform in very high resolution (due to zooming). The Waveform is drawn in a JScrollPane therefore. I want to be able to paint about 50.000-60.000 pixels width with it.
Unfortunately it stops painting properly at about 34000 pixel width. The issue is that it doesn't paint ca. the first screen size anymore, but the rest is drawn properly. As I only have very little experience in graphical stuff I thought you might be able to help me to decide how to fix this as best as possible.
I thought about dealing with it via repainting the first screen size (e.g. with repaint(Rectangle)) or maybe with parting the picture into 3 or more frames. If I choose the 2nd option I don't know if I should just part it an paint it all together or only paint it when its visible on the Viewport. Or maybe there is another better solution I cant figure out?
I hope you can help me with this and save me loads of hours to try out everything. Thanks in advance.
So here is the requested executable. You can see improper drawing at about 34.000 pixels width. Current pixels can be read in System.out . Drawing doesnt work with mp3, as not supported. I suggest tryouts with .wav.
Main Class:
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
public class Main {
private JFrame mainFrame;
private JPanel upperPanel;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Main window = new Main();
window.mainFrame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Initialize Application
*/
public Main() {
initializeMainFrame();
initializePanels();
}
private void initializePanels() {
upperPanel = new MainPanel();
upperPanel.setPreferredSize(new Dimension(1000, 500));
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.NORTH;
c.weightx = 1.0;
c.weighty = 1.0;
c.fill = GridBagConstraints.BOTH;
c.gridy = 0;
c.gridwidth = GridBagConstraints.REMAINDER;
mainFrame.add(upperPanel, c);
}
private void initializeMainFrame() {
mainFrame = new JFrame("Waveform Example");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GraphicsEnvironment ge = GraphicsEnvironment
.getLocalGraphicsEnvironment();
Rectangle gebounds = ge.getMaximumWindowBounds();
mainFrame.setSize(gebounds.getSize());
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
mainFrame.setLayout(new GridBagLayout());
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
JMenuItem importAudio = new JMenuItem("Import Audio");
menuBar.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.WEST;
c.weightx = 0.3;
c.weighty = 0.3;
c.gridx = 0;
c.gridy = 0;
mainFrame.setJMenuBar(menuBar);
menuBar.add(fileMenu, c);
c.gridx = 1;
c.gridy = 0;
fileMenu.add(importAudio);
importAudio.addActionListener(new importAudioActionListener());
}
private class importAudioActionListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent event) {
File f = getFile();
if (f != null) {
AudioInfo audioInfo = createAudioInfo(f);
mainFrame.remove(upperPanel);
upperPanel = new MainPanel(audioInfo);
upperPanel.setPreferredSize(new Dimension(1000, 500));
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.NORTH;
c.gridy = 0;
c.weightx = 1.0;
c.weighty = 1.0;
c.fill = GridBagConstraints.BOTH;
c.gridwidth = GridBagConstraints.REMAINDER;
mainFrame.add(upperPanel, c);
mainFrame.pack();
}
}
private AudioInfo createAudioInfo(File f) {
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.getAudioInputStream(f);
} catch (UnsupportedAudioFileException e1) {
System.out.println("Invalid Audio Format");
} catch (IOException e1) {
System.out.println("Invalid Input File");
}
AudioInfo retInfo = new AudioInfo(audioInputStream,
(int) f.length());
return retInfo;
}
private File getFile() {
// New file chooser only shows and accepts MP3 files.
JFileChooser fc = new JFileChooser();
fc.setAcceptAllFileFilterUsed(false);
fc.showOpenDialog(null);
File f = null;
try {
f = fc.getSelectedFile();
} catch (Exception fnfe) {
f = null;
System.out.println("File not found!");
}
return f;
}
}
}
Panel that contains JPanel:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class MainPanel extends JPanel implements MouseWheelListener,
ComponentListener {
private boolean finishedZoom = true;
private int mouseX;
private static final long serialVersionUID = 1L;
private AudioInfo audioInfo;
private int scale = 1;
private Dimension panelSize;
private int mouseXScaled;
private int mouseYScaled;
private JScrollPane scrollPane;
private int sizeNormalizer = 150;
private JPanel thisPanel = this;
private JPanel content;
public MainPanel() {
}
public MainPanel(AudioInfo audioInfo) {
this.audioInfo = audioInfo;
this.setLayout(new BorderLayout());
panelSize = new Dimension(1000, 500);
content = getContent();
scrollPane = new JScrollPane(content);
scrollPane.setPreferredSize(panelSize);
scrollPane
.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
this.add(scrollPane, BorderLayout.CENTER);
this.setPreferredSize(panelSize);
content.addMouseWheelListener(this);
content.addComponentListener(this);
}
private JPanel getContent() {
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.weightx = 1.0;
c.weighty = 1.0;
JPanel retContent = new JPanel(false);
retContent.setPreferredSize(panelSize);
retContent.setLayout(new GridBagLayout());
WaveformPanel waveformPanel = new WaveformPanel(audioInfo);
waveformPanel.setPreferredSize(panelSize);
retContent.setBackground(Color.green);
c.gridwidth = GridBagConstraints.REMAINDER; // end row
retContent.add(waveformPanel, c);
return retContent;
}
public void mouseWheelMoved(MouseWheelEvent e) {
boolean changed = false;
double notches = e.getWheelRotation();
if (e.isControlDown() && finishedZoom) {
int newScale = (int) (scale + notches * (-1) * 2);
int newWidth = (int) ((thisPanel.getPreferredSize().getWidth()) * newScale);
if (newWidth > content.getPreferredSize().getWidth()) {
System.out.println("new width original: " + newWidth);
content.setVisible(false);
content.setPreferredSize(new Dimension(
newWidth,
(int) ((thisPanel.getPreferredSize().getHeight() - sizeNormalizer) / 3 * 2)));
content.setVisible(true);
mouseXScaled = e.getX() / scale * newScale;
mouseYScaled = e.getY() / scale * newScale;
scale = newScale;
changed = true;
} else if (newWidth < content.getPreferredSize().getWidth()
&& newWidth > thisPanel.getWidth()) {
content.setVisible(false);
content.setPreferredSize(new Dimension(
newWidth,
(int) ((thisPanel.getPreferredSize().getHeight() - sizeNormalizer) / 3 * 2)));
content.setVisible(true);
mouseXScaled = e.getX() / scale * newScale;
mouseYScaled = e.getY() / scale * newScale;
scale = newScale;
changed = true;
} else if (newWidth <= thisPanel.getWidth()) {
newWidth = (int) (thisPanel.getPreferredSize().getWidth());
newScale = 1;
content.setVisible(false);
content.setPreferredSize(new Dimension(
newWidth,
(int) ((thisPanel.getPreferredSize().getHeight() - sizeNormalizer) / 3 * 2)));
content.setVisible(true);
mouseXScaled = e.getX() / scale * newScale;
mouseYScaled = e.getY() / scale * newScale;
scale = newScale;
}
if (changed) {
finishedZoom = false;
}
mouseX = e.getX();
} else if (!e.isControlDown()) {
int scrollBarValue = scrollPane.getHorizontalScrollBar().getValue();
Rectangle viewRect = scrollPane.getViewport().getViewRect();
scrollPane
.getHorizontalScrollBar()
.setValue(
(int) ((int) scrollBarValue + ((viewRect.width - 100) * notches)));
}
}
public int getHorizontalScroll() {
return scrollPane.getHorizontalScrollBar().getValue();
}
#Override
public void componentHidden(ComponentEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void componentMoved(ComponentEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void componentResized(ComponentEvent arg0) {
if (mouseXScaled != 0 && mouseYScaled != 0) {
int scrollBarVal = scrollPane.getHorizontalScrollBar().getValue();
int newX = (int) (scrollBarVal + mouseXScaled - mouseX);
scrollPane.getHorizontalScrollBar().setValue(newX);
finishedZoom = true;
}
}
#Override
public void componentShown(ComponentEvent arg0) {
// TODO Auto-generated method stub
}
}
AudioInfo Class:
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
public class AudioInfo {
private static final int NUM_BITS_PER_BYTE = 8;
private AudioInputStream encodedInputSream;
private int[][] encodedSamplesContainer;
private byte[] encodedBuffer;
// cached values
private int sampleMax = 0;
private int sampleMin = 0;
private double biggestSample;
public AudioInfo(AudioInputStream encodedInputStream, int fileSize) {
encodedBuffer = new byte[fileSize];
this.encodedInputSream = encodedInputStream;
encodedBuffer = createSampleArrayCollection(encodedInputStream,
encodedBuffer);
encodedSamplesContainer = getSampleArray(encodedBuffer);
if (sampleMax > sampleMin) {
biggestSample = sampleMax;
} else {
biggestSample = Math.abs(((double) sampleMin));
}
}
protected int getNumberOfChannels() {
return 2;
}
/**
* Reads the audio input stream into a tmp array and then inserts the tmp
* array into a buffer array. Resets the mark of the audio input stream
* after finish buffering. Then cuts the array from fileSize*10 to the final
* size.
*/
private byte[] createSampleArrayCollection(AudioInputStream inputStream,
byte[] inBuffer) {
byte[] buffer = new byte[inBuffer.length];
int sumReadBytes = 0;
try {
// inputStream.mark(Integer.MAX_VALUE);
//inputStream.reset();
boolean end = false;
while (!end) {
int available = inputStream.available();
if (available <= 0) {
end = true;
}
if (!end) {
byte[] tmp = new byte[available];
int readBytes = inputStream.read(tmp);
tmp = cutArray(tmp, readBytes);
insertArray(buffer, tmp, sumReadBytes);
sumReadBytes += readBytes;
}
}
//inputStream.reset();
} catch (IOException e) {
e.printStackTrace();
}
buffer = cutArray(buffer, sumReadBytes);
return buffer;
}
/**
*
* #param cutThis
* array that has to be cut
* #param cutPoint
* index at which the array will be cut off
* #return the buffer array cut off at the point of cutpoint
*/
private byte[] cutArray(byte[] cutThis, int cutPoint) {
byte[] tmp = new byte[cutPoint];
for (int i = 0; i < tmp.length; i++) {
tmp[i] = cutThis[i];
}
return tmp;
}
/**
*
* #param insertIntoThis
* the array you want to insert in the other
* #param tmp
* the array that is going to be inserted
*/
private byte[] insertArray(byte[] insertIntoThis, byte[] tmp,
int nextEmptyField) {
for (int i = 0; i < tmp.length; i++) {
insertIntoThis[nextEmptyField] = tmp[i];
nextEmptyField++;
}
return insertIntoThis;
}
/**
*
* #param eightBitByteArray
* Array of an eight bit byte array.
* #return int audio information array for every channel.
*/
private int[][] getSampleArray(byte[] eightBitByteArray) {
int[][] toReturn = new int[getNumberOfChannels()][eightBitByteArray.length
/ (2 * getNumberOfChannels()) + 1];
int index = 0;
// loop through the byte[]
for (int t = 0; t + 4 < eightBitByteArray.length;) {
// for each iteration, loop through the channels
for (int a = 0; a < getNumberOfChannels(); a++) {
// do the byte to sample conversion
// see AmplitudeEditor for more info
int low = (int) eightBitByteArray[t];
t++;
int high = (int) eightBitByteArray[t];
t++;
int sample = (high << 8) + (low & 0x00ff);
if (sample < sampleMin) {
sampleMin = sample;
} else if (sample > sampleMax) {
sampleMax = sample;
}
// set the value.
toReturn[a][index] = sample;
}
index++;
}
return toReturn;
}
/**
*
* #param panelHeight
* #return calculated yScaleFactor
*/
public double getYScaleFactor(int panelHeight) {
return (panelHeight / (biggestSample * 2 * 1.5));
}
/**
*
* #param channel
* number of the channel you want the audio information of
* #return int array of the audio information of the given channel.
*/
protected int[] getAudio(int channel) {
return encodedSamplesContainer[channel];
}
/**
*
* #param xScale
* #return calculates the increment for given xScale
*/
protected int getIncrement(double xScale) {
try {
int increment = (int) (encodedSamplesContainer[0].length / (encodedSamplesContainer[0].length * xScale));
return increment;
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
}
Waveform Panel Class:
import javax.swing.*;
import java.awt.*;
public class WaveformPanel extends JPanel {
private static final long serialVersionUID = 1L;
private static final Color BACKGROUND_COLOR = Color.black;
private static final Color REFERENCE_LINE_COLOR = Color.blue;
private static final Color WAVEFORM_COLOR = Color.blue;
private AudioInfo helper;
private int[] samples;
public WaveformPanel(AudioInfo helper) {
super();
this.helper = helper;
setBackground(BACKGROUND_COLOR);
samples = helper.getAudio(0);
}
/**
* Paints the component of the melted channel audio data.
*/
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int lineHeight = getHeight() / 2;
g.setColor(REFERENCE_LINE_COLOR);
g.drawLine(0, lineHeight, (int) getWidth(), lineHeight);
drawWaveform(g, samples);
}
protected double getXScaleFactor(int panelWidth) {
double width = (double) panelWidth;
return (width / ((double) samples.length));
}
private double getIncrement(double xScale) {
try {
double increment = (samples.length / (samples.length * xScale));
return increment;
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
/**
* #param g
* graphic of this panel
* #param samples
* audio samples of a channel
*
* Draws a waveform with given input on a graphic.
*/
protected void drawWaveform(Graphics g, int[] samples) {
int buffer = 30;
if (samples == null) {
return;
}
double oldX = 0;
double xIndex = 0;
double increment = getIncrement(getXScaleFactor(getWidth() - buffer * 2));
g.setColor(WAVEFORM_COLOR);
System.out.println("width: " + this.getWidth());
double t = 0;
int drawLength = samples.length;
for (; t < drawLength; t += increment) {
double scaleFactor = helper.getYScaleFactor(getHeight());
double scaledSample = samples[(int) t] * scaleFactor;
double y = ((getHeight() / 2) - (scaledSample));
double yMirror = ((getHeight() / 2) + scaledSample);
g.drawLine((int) (oldX + buffer), (int) yMirror,
(int) (xIndex + buffer), (int) y);
xIndex++;
oldX = xIndex;
}
}
}
As an alternative, see this MCTaRE that successfully renders an image that is twice that width. Scroll it to half width (or any width for that matter) to see ..the image with no artifacts.
Note that I called setPreferredSize in that example to save a few code lines, but see Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing? (Yes.)
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
class BigImageWaveform {
public static void main(String[] args) {
final BufferedImage bi = new BufferedImage(
2*34000, 500, BufferedImage.TYPE_INT_RGB);
draw(bi);
Runnable r = new Runnable() {
#Override
public void run() {
JScrollPane jsp = new JScrollPane(
new JLabel(new ImageIcon(bi)),
JScrollPane.VERTICAL_SCROLLBAR_NEVER,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
Dimension d = jsp.getPreferredSize();
jsp.setPreferredSize(new Dimension(1000, (int)d.getHeight()));
JOptionPane.showMessageDialog(null, jsp);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
public static void draw(BufferedImage bi) {
Graphics2D g = bi.createGraphics();
int w = bi.getWidth();
int h = bi.getHeight();
GradientPaint gp = new GradientPaint(
0f,0f,Color.RED,
101f,0f,Color.GREEN,true);
g.setPaint(gp);
g.fillRect(0,0,w,h);
gp = new GradientPaint(
0f,0f,new Color(0,0,255,128),
97f,103f,new Color(220,0,220,164), true);
g.setPaint(gp);
g.fillRect(0,0,w,h);
gp = new GradientPaint(
0f,0f,new Color(0,0,0,0),
(float)w,0f,new Color(0,0,0,128), true);
g.setPaint(gp);
g.fillRect(0,0,w,h);
g.dispose();
}
}
After testing this on two more potent Windows Systems I came to the opinion that its either a Linux problem or a performance problem, as my laptop is about 2 years old and was pretty cheap.
If anybody could test it out on a Linux System it would be great. Otherwise I am going to mark this issue as answered.