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.
Related
I have been trying very hard these past days to understand Graphics2d. I do understand the shapes an all, however I can not draw a simple Graph with it.
My Goal is to draw a Coordinate System, that you can change its length if you want to. Like you say the min x Value would be -5 and the max x Value would be 10 and it would scale it self to it and the function too. However I have a really big Problem just creating and scaling the axis correctly. I think this just comes from a high not understanding everything correctly. This is why I would be glad if someone could help me with this matter.
Here is the code I have been working on. It is absolutely not finished. However I would like to get the scaling and all right. But ever other correction is gladly welcomed, due to me being a newbie in java.
I also tried to make it that if like min x would be positive there would be no x axis. Which just does not work.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
public class GraphPlotter extends JFrame {
//f(x) = ax² + bx + c
//Knöpfe
private JButton _ploten = new JButton("Plot");
private JButton _limits = new JButton("Limits");
//Text
private JLabel _funk = new JLabel("f(x) =");
private JLabel _x2 = new JLabel("x² +");
private JLabel _x = new JLabel("x +");
private JLabel _xmin = new JLabel("X min");
private JLabel _ymin = new JLabel("Y min");
private JLabel _ymax = new JLabel("Y max");
private JLabel _xmax = new JLabel("X max");
private String _nummber = "0";
//Textfelder
private JTextField _a = new JTextField(_nummber, 3);
private JTextField _b = new JTextField(_nummber, 3);
private JTextField _c = new JTextField(_nummber, 3);
private JTextField _xMinField = new JTextField("-10");
private JTextField _xMaxField = new JTextField("10");
private JTextField _yMinField = new JTextField("-10");
private JTextField _yMaxField = new JTextField("10");
//Felder
private JPanel _top = new JPanel();
private JPanel _zoom = new JPanel();
private JPanel _graph = new Graph();
public GraphPlotter() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(500, 500);
setTitle("Graph Plotter");
//Alignment
_funk.setAlignmentX(Component.CENTER_ALIGNMENT);
_x2.setAlignmentX(Component.CENTER_ALIGNMENT);
_x.setAlignmentX(Component.CENTER_ALIGNMENT);
_ploten.setAlignmentX(Component.CENTER_ALIGNMENT);
_a.setAlignmentX(Component.CENTER_ALIGNMENT);
_b.setAlignmentX(Component.CENTER_ALIGNMENT);
_c.setAlignmentX(Component.CENTER_ALIGNMENT);
//So if you click on the TextField that it marks it
_a.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent fe) {
_a.setSelectionStart(0);
_a.setSelectionEnd(_a.getText().length());
}
});
_b.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent fe) {
_b.setSelectionStart(0);
_b.setSelectionEnd(_b.getText().length());
}
});
_c.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent fe) {
_c.setSelectionStart(0);
_c.setSelectionEnd(_c.getText().length());
}
});
_xMinField.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent fe) {
_xMinField.setSelectionStart(0);
_xMinField.setSelectionEnd(_xMinField.getText().length());
}
});
_xMaxField.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent fe) {
_xMaxField.setSelectionStart(0);
_xMaxField.setSelectionEnd(_xMaxField.getText().length());
}
});
_yMinField.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent fe) {
_yMinField.setSelectionStart(0);
_yMinField.setSelectionEnd(_yMinField.getText().length());
}
});
_yMaxField.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent fe) {
_yMaxField.setSelectionStart(0);
_yMaxField.setSelectionEnd(_yMaxField.getText().length());
}
});
//Aktions for the buttons
_ploten.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
//draw a new function
}
});
_limits.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
//reskale the Graph
}
});
//Layouts
//Main
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 20;
c.gridwidth = 3;
c.gridx = 0;
c.gridy = 0;
add(_top, c);
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.fill = GridBagConstraints.BOTH;
c.weightx = 1.0;
c.gridwidth = 2;
c.gridx = 0;
c.gridy = 1;
add(_graph, c);
c.anchor = GridBagConstraints.FIRST_LINE_END;
c.fill = GridBagConstraints.VERTICAL;
c.weightx = 0.0;
c.weighty = 0.5;
c.ipadx = 20;
c.gridwidth = 1;
c.gridx = 2;
c.gridy = 1;
add(_zoom, c);
//Skalling
_zoom.setLayout(new BoxLayout(_zoom, BoxLayout.PAGE_AXIS));
//Borders to better see the layout
_top.setBorder(BorderFactory.createStrokeBorder(new BasicStroke(5.0f)));
_graph.setBorder(BorderFactory.createStrokeBorder(new BasicStroke(5.0f)));
_zoom.setBorder(BorderFactory.createStrokeBorder(new BasicStroke(5.0f)));
_top.add(_funk);
_top.add(_a);
_top.add(_x2);
_top.add(_b);
_top.add(_x);
_top.add(_c);
_top.add(_ploten);
_zoom.add(_xmin);
_zoom.add(_xMinField);
_zoom.add(_xmax);
_zoom.add(_xMaxField);
_zoom.add(_ymin);
_zoom.add(_yMinField);
_zoom.add(_ymax);
_zoom.add(_yMaxField);
_zoom.add(_limits);
setVisible(true);
}
public class Graph extends JPanel {
Color[] _color = {Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW, Color.MAGENTA, Color.CYAN, Color.ORANGE, Color.PINK};
int c = 0;
int _width;
int _hight;
int _diffX;
int _diffY;
int _midx;
int _midy;
int xMAX;
int xMIN;
int yMAX;
int yMIN;
public void paintComponent(Graphics g) {
_width = getWidth();
_hight = getHeight();
//Max und Min
xMAX = Integer.parseInt(_xMaxField.getText());
xMIN = Integer.parseInt(_xMinField.getText());
yMAX = Integer.parseInt(_yMaxField.getText());
yMIN = Integer.parseInt(_yMinField.getText());
//Diff
_diffX = xMAX + xMIN;
_diffY = yMAX + yMIN;
if (!(xMIN > 0) && !(xMAX < 0)) {
_midx = (_width / 2) - _diffX;
} else {
_midx = 0;
}
if (!(yMIN > 0) && !(yMAX < 0)) {
_midy = (_hight /2) - _diffY;
} else {
_midy = 0;
}
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
drawAxis(g2D);
}
private void drawAxis(Graphics2D g2d) {
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(2));
//X-Achse
if (!(xMIN > 0) && !(xMAX < 0)) {
g2d.drawLine(0, _midy, _width, _midy);
}
//Y-Achse
if (!(yMIN > 0) && !(yMAX < 0)) {
g2d.drawLine(_midx, 0, _midx, _hight);
}
//Scales drawing
g2d.setStroke(new BasicStroke(1));
for (int n = 0; n < _width; n = n + 5) {
g2d.drawLine(n + _midx, _midy, n + _midx, _midy + 5);
g2d.drawLine(n - _midx, _midy, n - _midx, _midy + 5);
}
for (int n = 0; n < _hight; n = n +5) {
g2d.drawLine(_midx, n + _midy, _midx - 5, n + _midy);
g2d.drawLine(_midx, n - _midy, _midx - 5, n - _midy);
}
}
private void drawGraph(Graphics2D g2d) {
if (!(Integer.parseInt(_a.getText()) == 0) && !(Integer.parseInt(_b.getText()) == 0) && !(Integer.parseInt(_c.getText())== 0)) {
}
}
}
}
Introduction
Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section. Pay particular attention to the Performing Custom Painting section.
I reworked your GUI. Here's what it looks like now.
I move the X and Y axis around so that the graph fits in the drawing area. The minimum and maximum V values are no less than -10 and 10, respectively. I show the calculated Y minimum and maximum values in the entry panel. The X axis and Y axis are not to the same scale.
Explanation
When I create a Swing GUI, I use the model-view-controller (MVC) pattern. This pattern helps me to separate my concerns and focus on one small part of the application at a time.
The application model for a Swing GUI consists of one or more plain Java getter/setter classes.
The view consists of one and only one JFrame and as many JPanels as I need to create the GUI. You can nest multiple simple JPanels to create a complex layout.
The controller consists of one or more Actions or Listeners. There's usually not one controller to "rule them all". Each Action or Listener is responsible for its part of the model and view.
I didn't write all the code at once. I wrote a little and tested a lot. I probably ran 150 - 200 tests of the GUI before I was satisfied.
Model
I created one plain Java getter/setter class, the GraphPlotterModel class. This class holds the X and Y minimum and maximum values, and a java.util.List of Point2D instances that make up the graph. I also define a starting Dimension in pixels for the drawing JPanel. The dimensions of the drawing JPanel can change. One way is to maximize the GUI.
The model also holds the calculation of the quadratic equation. I go from the X minimum to the X maximum, calculating the corresponding Y value. The X and Y values are in units.
View
I started the GUI with a call to the SwingUtilities invokeLater method. This method ensures that the Swing components are created and executed on the Event Dispatch Thread.
I separated the creation of the JFrame from the creation of the JPanels. This allows me to separate my concerns and focus on one small part of the application at a time. The top JPanel is made up of two individual JPanels, one for the title and one for the entry fields. The center JPanel is a standard drawing panel.
Generally, you define Swing components on a JPanel in column, row order. This makes the code easier to read and understand.
The drawing panel has a method to convert units to pixels. This method probably took 1/3 of my total development time. The biggest hurdle is that a standard graph goes up from the Y minimum to the Y maximum and the Y pixels go from top to bottom. I basically use ratios to calculate the pixels.
Controller
There's only one JButton, so there's only one ActionListener. I made it a separate private class because it has a lot of code and I didn't want to have to pass 5 input fields to a separate class. I check to make sure all the inputs are valid double values, but I didn't display any error message.
Code
Here's the complete runnable code. I made all the additional public classes inner classes so I could post the code as one block.
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class GraphPlotter implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new GraphPlotter());
}
private final GraphPlotterModel model;
private final DrawingPanel drawingPanel;
private JTextField aField, bField, cField;
private JTextField xMinField, xMaxField, yMinField, yMaxField;
public GraphPlotter() {
this.model = new GraphPlotterModel();
this.drawingPanel = new DrawingPanel(model);
}
#Override
public void run() {
JFrame frame = new JFrame("Graph Plotter");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createEntryPanel(), BorderLayout.NORTH);
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createEntryPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
Font font = panel.getFont().deriveFont(16f);
Font titleFont = panel.getFont().deriveFont(Font.BOLD, 24f);
JPanel titlePanel = new JPanel(new FlowLayout());
titlePanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
JLabel label = new JLabel(
"Plot the quadratic equation f(x) = ax² + bx + c");
label.setFont(titleFont);
titlePanel.add(label);
JPanel entryPanel = new JPanel(new FlowLayout());
entryPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
label = new JLabel("f(x) =");
label.setFont(font);
entryPanel.add(label);
aField = new JTextField(5);
aField.setFont(font);
entryPanel.add(aField);
label = new JLabel("x² +");
label.setFont(font);
entryPanel.add(label);
bField = new JTextField(5);
bField.setFont(font);
entryPanel.add(bField);
label = new JLabel("x +");
label.setFont(font);
entryPanel.add(label);
cField = new JTextField(5);
cField.setFont(font);
entryPanel.add(cField);
entryPanel.add(Box.createHorizontalStrut(30));
label = new JLabel("X min:");
label.setFont(font);
entryPanel.add(label);
xMinField = new JTextField(5);
xMinField.setFont(font);
entryPanel.add(xMinField);
label = new JLabel("X max:");
label.setFont(font);
entryPanel.add(label);
xMaxField = new JTextField(5);
xMaxField.setFont(font);
entryPanel.add(xMaxField);
label = new JLabel("Y min:");
label.setFont(font);
entryPanel.add(label);
yMinField = new JTextField(5);
yMinField.setEditable(false);
yMinField.setFont(font);
entryPanel.add(yMinField);
label = new JLabel("Y max:");
label.setFont(font);
entryPanel.add(label);
yMaxField = new JTextField(5);
yMaxField.setEditable(false);
yMaxField.setFont(font);
entryPanel.add(yMaxField);
entryPanel.add(Box.createHorizontalStrut(30));
JButton button = new JButton("Plot");
button.addActionListener(new PlotListener());
button.setFont(font);
entryPanel.add(button);
updateEntryPanel();
panel.add(titlePanel, BorderLayout.NORTH);
panel.add(entryPanel, BorderLayout.SOUTH);
return panel;
}
public void updateEntryPanel() {
String formatter = "%.2f";
aField.setText(String.format(formatter, model.getA()));
bField.setText(String.format(formatter, model.getB()));
cField.setText(String.format(formatter, model.getC()));
xMinField.setText(String.format(formatter, model.getxMin()));
xMaxField.setText(String.format(formatter, model.getxMax()));
yMinField.setText(String.format(formatter, model.getyMin()));
yMaxField.setText(String.format(formatter, model.getyMax()));
}
public void repaint() {
drawingPanel.repaint();
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private final int margin;
private final GraphPlotterModel model;
public DrawingPanel(GraphPlotterModel model) {
this.model = model;
this.margin = 20;
this.setPreferredSize(model.getDrawingAreaDimension());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(3f));
int width = getWidth() - margin - margin;
int height = getHeight() - margin - margin;
double xMin = model.getxMin();
double xMax = model.getxMax();
double yMin = model.getyMin();
double yMax = model.getyMax();
// Draw X Axis
Point2D a = new Point2D.Double(xMin, 0.0);
Point2D b = new Point2D.Double(xMax, 0.0);
Point startPoint = toPixels(a, width, height);
Point endPoint = toPixels(b, width, height);
g2d.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y);
// Draw Y axis
a = new Point2D.Double(0.0, yMin);
b = new Point2D.Double(0.0, yMax);
startPoint = toPixels(a, width, height);
endPoint = toPixels(b, width, height);
g2d.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y);
// Draw graph
g2d.setColor(Color.BLUE);
Point previousPoint = null;
List<Point2D> points = model.getPoints();
for (Point2D point : points) {
Point drawPoint = toPixels(point, width, height);
// System.out.println(point + " " + drawPoint);
if (previousPoint != null) {
g2d.drawLine(previousPoint.x, previousPoint.y, drawPoint.x,
drawPoint.y);
}
previousPoint = (Point) drawPoint.clone();
}
}
private Point toPixels(Point2D point, int width, int height) {
double xMin = model.getxMin();
double xMax = model.getxMax();
double yMin = model.getyMin();
double yMax = model.getyMax();
// System.out.println(yMin + " " + yMax);
double xDelta = (xMax - xMin) / width;
double yDelta = (yMax - yMin) / height;
double xx = Math.round((point.getX() - xMin) / xDelta);
double yy = Math.round((point.getY() - yMin) / yDelta);
// X in pixels goes from left to right
int x = (int) xx + margin;
// Y in pixels goes from top to bottom
int y = height - (int) yy + margin;
return new Point(x, y);
}
}
private class PlotListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent event) {
String aString = aField.getText().trim();
String bString = bField.getText().trim();
String cString = cField.getText().trim();
String xMinString = xMinField.getText().trim();
String xMaxString = xMaxField.getText().trim();
double a = valueOf(aString);
if (a == Double.MIN_VALUE) {
return;
}
double b = valueOf(bString);
if (b == Double.MIN_VALUE) {
return;
}
double c = valueOf(cString);
if (c == Double.MIN_VALUE) {
return;
}
double xMin = valueOf(xMinString);
if (xMin == Double.MIN_VALUE) {
return;
}
double xMax = valueOf(xMaxString);
if (xMax == Double.MIN_VALUE) {
return;
}
model.setA(a);
model.setB(b);
model.setC(c);
model.setxMin(xMin);
model.setxMax(xMax);
model.calculatePlot();
updateEntryPanel();
repaint();
}
private double valueOf(String s) {
try {
return Double.valueOf(s);
} catch (NumberFormatException e) {
return Double.MIN_VALUE;
}
}
}
public class GraphPlotterModel {
/** f(x) = ax² + bx + c */
private double a, b, c, xMin, xMax, yMin, yMax;
private final List<Point2D> points;
private final Dimension drawingAreaDimension;
public GraphPlotterModel() {
this.drawingAreaDimension = new Dimension(500, 500);
this.points = new ArrayList<>();
this.xMin = -10.0;
this.xMax = 10.0;
this.yMin = -10.0;
this.yMax = 10.0;
}
public void calculatePlot() {
// steps should be an even number
int steps = 100;
double xDelta = (xMax - xMin) / steps;
double x = xMin;
double yMin = Double.MAX_VALUE;
double yMax = Double.MIN_VALUE;
points.clear();
for (int index = 0; index <= steps; index++) {
double y = a * x * x + b * x + c;
Point2D point = new Point2D.Double(x, y);
points.add(point);
x += xDelta;
yMax = Math.max(yMax, y);
yMin = Math.min(yMin, y);
}
// Make sure that Y goes from -10 to 10 at a minimum
this.yMax = Math.max(yMax, 10.0);
this.yMin = Math.min(yMin, -10.0);
}
public Dimension getDrawingAreaDimension() {
return drawingAreaDimension;
}
public double getA() {
return a;
}
public void setA(double a) {
this.a = a;
}
public double getB() {
return b;
}
public void setB(double b) {
this.b = b;
}
public double getC() {
return c;
}
public void setC(double c) {
this.c = c;
}
public double getxMin() {
return xMin;
}
public void setxMin(double xMin) {
this.xMin = xMin;
}
public double getxMax() {
return xMax;
}
public void setxMax(double xMax) {
this.xMax = xMax;
}
public List<Point2D> getPoints() {
return points;
}
public double getyMin() {
return yMin;
}
public double getyMax() {
return yMax;
}
}
}
I am coding a little Asteroids game, but it seems to be lagging a little bit. I am using a swing.Timer in order to update my JFrame and display the graphics. I have two questions,
the first one being:
"Could the timer be the reason for the lags?" and the second one being:
"Is using a Timer the optimal way to handle game programming in Java, or is it not?"
When browsing the net, it seemed like everyone is using a Timer in order to handle animations, but I can't help but feel that it is a suboptimal way of doing this. Can someone pls explain this to me? Thank you in advance :)
Here is the code of my Timer, if it helps. First the Base class:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class Base implements ActionListener {
// Attributes
protected static int cd = 3; // Length of Countdown in seconds
private int nrOfAsteroids = 10; // Amount of Asteroids spawned
protected static int fps = 60; // Frames-per-second
// Various variables and constants
protected static BufferedImage image;
protected static int height;
protected static int width;
protected static boolean colorMode = false;
// Variables needed for Key-register
protected static boolean isWpressed = false;
private boolean isQpressed = false;
private boolean isEpressed = false;
private boolean isSpacePressed = false;
private boolean stop = false; // TODO remove after game is finished
// Various complex-objects
private static Base b = new Base();
private Asteroid[] a = new Asteroid[nrOfAsteroids];
private JFrame frame;
private JButton start;
private JButton colorButton;
private JLabel dummy;
private JLabel gameLabel;
protected static JLabel screen = new JLabel();
private ImageIcon icon;
private Timer t;
private static Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
public static void main(String[] args) {
height = (int) (screenSize.height * 0.9);
width = (int) (screenSize.width * 0.9);
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
screen.setSize(width, height);
b.frameSetup();
} // end main
private void frameSetup() {
// Frame Setup
frame = new JFrame("yaaasssss hemorrhoids");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.BLACK);
frame.setBounds((int) (screenSize.width * 0.05), (int) (screenSize.height * 0.03), width, height);
frame.setLayout(new GridBagLayout());
// creating a "color" button
colorButton = new JButton("CLASSIC");
GridBagConstraints cb = new GridBagConstraints();
cb.weightx = 1;
cb.weighty = 1;
cb.gridx = 2;
cb.gridy = 0;
cb.anchor = GridBagConstraints.FIRST_LINE_END;
cb.insets = new Insets(10, 0, 0, 10);
colorButton.setPreferredSize(new Dimension(100, 30));
frame.add(colorButton, cb);
// creating a "ASTEROIDS" Label
gameLabel = new JLabel("ASSTEROIDS");
GridBagConstraints gl = new GridBagConstraints();
gl.weightx = 1;
gl.weighty = 1;
gl.gridwidth = 3;
gl.gridx = 0;
gl.gridy = 1;
gl.anchor = GridBagConstraints.CENTER;
gl.fill = GridBagConstraints.BOTH;
gameLabel.setPreferredSize(new Dimension(100, 30));
gameLabel.setFont(gameLabel.getFont().deriveFont(60.0f));
gameLabel.setForeground(Color.WHITE);
gameLabel.setHorizontalAlignment(SwingConstants.CENTER);
frame.add(gameLabel, gl);
// Dummy Component
dummy = new JLabel();
GridBagConstraints dc = new GridBagConstraints();
dummy.setPreferredSize(new Dimension(100, 30));
dc.weightx = 1;
dc.weighty = 1;
dc.gridx = 0;
dc.gridy = 0;
frame.add(dummy, dc);
// creating a "start" button
start = new JButton("START");
GridBagConstraints sb = new GridBagConstraints();
sb.weightx = 1;
sb.weighty = 1;
sb.gridx = 1;
sb.gridy = 2;
sb.anchor = GridBagConstraints.PAGE_START;
sb.insets = new Insets(15, 0, 0, 0);
start.setPreferredSize(new Dimension(100, 30));
frame.add(start, sb);
// Implementing a function to the buttons
start.addActionListener(this);
colorButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (colorButton.getText() == "CLASSIC") {
colorMode = true;
colorButton.setText("LSD-TRIP");
} else {
colorMode = false;
colorButton.setText("CLASSIC");
}
}
});
// Show Results
frame.setVisible(true);
}
private void addImage() {
// Implementing the Image
icon = new ImageIcon(image);
screen.setIcon(icon);
frame.add(screen);
}
protected void setWindowSize() {
width = frame.getBounds().width;
height = frame.getBounds().height;
screen.setSize(width, height);
}
#Override
public void actionPerformed(ActionEvent ae) {
// Cleaning the screen
frame.remove(start);
frame.remove(gameLabel);
frame.remove(colorButton);
frame.remove(dummy);
// Checking if Window has been resized, and acting according to it
setWindowSize();
// Creating the image
for (int i = 0; i < nrOfAsteroids; ++i) {
a[i] = new Asteroid();
}
gameStart();
}
private void gameStart() {
t = new Timer(1000/fps, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
clearScreen();
for (int i = 0; i < nrOfAsteroids; ++i) {
a[i].drawAsteroid();
}
// Managing Controlls
if (isWpressed) {}
if (isQpressed) { }
if (isEpressed) { }
if (isSpacePressed) { }
if (stop) { }
// Updating the screen
b.addImage();
}
});
t.setInitialDelay(0);
actions();
t.start();
}
private void actions() {
// Defining all the constants for more order when handling the actions
final int focus = JComponent.WHEN_IN_FOCUSED_WINDOW;
String move = "Movement started";
String noMove = "Movement stopped";
String shoot = "Shooting started";
String noShoot = "Shooting stopped";
String turnLeft = "Rotation left started";
String noTurnLeft = "Rotation left stopped";
String turnRight = "Rotation right started";
String noTurnRight = "Rotation right stopped";
String stopIt = "stop"; // TODO remove when game is finished
// Getting the input and trigger an ActionMap
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("W"), move);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("released W"), noMove);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("SPACE"), shoot);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("released SPACE"), noShoot);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("Q"), turnLeft);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("released Q"), noTurnLeft);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("E"), turnRight);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("released E"), noTurnRight);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("S"), stopIt);
// Triggered ActionMaps perform an Action
screen.getActionMap().put(move, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isWpressed = true;
} });
screen.getActionMap().put(noMove, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isWpressed = false;
} });
screen.getActionMap().put(shoot, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isSpacePressed = true;
} });
screen.getActionMap().put(noShoot, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isSpacePressed = false;
} });
screen.getActionMap().put(turnLeft, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isQpressed = true;
} });
screen.getActionMap().put(noTurnLeft, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isQpressed = false;
} });
screen.getActionMap().put(turnRight, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isEpressed = true;
} });
screen.getActionMap().put(noTurnRight, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isEpressed = false;
} });
screen.getActionMap().put(stopIt, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
stop = true;
} });
} // end actions()
private void clearScreen() {
Graphics2D pen = image.createGraphics();
pen.clearRect(0, 0, Base.width, Base.height);
}
} // end class
Now the Asteroid class:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Polygon;
public class Asteroid {
// Attributes
private int amountOfCornerPoints = 12;
private int size = 50;
private int rotationSpeed = 2;
private int movementSpeed = 3;
// Fields needed to construct the Asteroid
private Polygon asteroidShape;
private int xCenter = (int) (Math.random() * Base.width);
private int yCenter = (int) (Math.random() * Base.height);
private int[] y = new int[amountOfCornerPoints];
private int[] x = new int[amountOfCornerPoints];
private int[] random = new int[amountOfCornerPoints];
private int rmax = 20; //Das Maximum für r
private int rmin = -rmax; //Das Minimum für r
// Field needed to transport the Asteroid
private boolean transporting = false;
// Field needed to rotate the Asteroid
private int cornerAddition = 0;
// Fields needed to detect Collision
// Fields needed to determine the direction of the Asteroid
private int direction = (int) Math.round((Math.random()*7));
private int xMove = 0;
private int yMove = 0;
// Fields for determining the color of the Asteroid
private Color col;
private int red = 255;
private int green = 255;
private int blue = 255;
public Asteroid() {
// Activating colorMode
if (Base.colorMode == true) {
do {
red = (int) Math.round((Math.random()*127));
green = (int) Math.round((Math.random()*127));
blue = (int) Math.round((Math.random()*127));
} while (red < 64 && green < 64 && blue < 64); }
col = new Color(red, green, blue);
// Zufallszahlen Generator
for (int i = 0; i < random.length; ++i) {
random[i] = (int) (Math.random()*rmax + rmin); }
asteroidShape = new Polygon();
whichDirection();
}
protected void drawAsteroid() {
move();
rotate();
int degreeHolder;
int degrees;
for (int i = 0; i < amountOfCornerPoints; ++i) {
degreeHolder = i*(360/amountOfCornerPoints) + cornerAddition;
if (degreeHolder >= 360) {
degrees = degreeHolder - 360;
} else {
degrees = degreeHolder;
}
x[i] = getXvalue(size + random[i])[degrees];
y[i] = getYvalue(size + random[i])[degrees];
}
asteroidShape.invalidate();
asteroidShape = new Polygon(x, y, amountOfCornerPoints);
Graphics2D pen = Base.image.createGraphics();
pen.setColor(col);
pen.draw(asteroidShape);
pen.dispose();
}
private void rotate() {
cornerAddition += rotationSpeed;
if (cornerAddition >= 360)
cornerAddition = cornerAddition - 360;
}
private void move() {
detectTransport();
xCenter += xMove;
yCenter += yMove;
}
private void detectTransport() {
boolean transportImmunity = false;
if (xCenter <= -size || xCenter >= Base.width + size) {
if (transportImmunity == false)
transporting = !transporting;
transportImmunity = true;
transport();
}
if (yCenter <= -size || yCenter >= Base.height + size) {
if (transportImmunity == false)
transporting = !transporting;
transportImmunity = true;
transport();
}
}
private void transport() {
while (transporting) {
xCenter -= xMove;
yCenter -= yMove;
detectTransport();
}
}
private void whichDirection() {
switch (direction) {
case 0: // Gerade Oben
xMove = 0;
yMove = -movementSpeed;
break;
case 1: // Diagonal Oben-rechts
xMove = movementSpeed;
yMove = -movementSpeed;
break;
case 2: // Gerade rechts
xMove = movementSpeed;
yMove = 0;
break;
case 3: // Diagonal Unten-rechts
xMove = movementSpeed;
yMove = movementSpeed;
break;
case 4: // Gerade Unten
xMove = 0;
yMove = movementSpeed;
break;
case 5: // Diagonal Unten-links
xMove = -movementSpeed;
yMove = movementSpeed;
break;
case 6: // Gerade links
xMove = -movementSpeed;
yMove = 0;
break;
case 7: // Diagonal Oben-links
xMove = -movementSpeed;
yMove = -movementSpeed;
break;
}
} // end WhichDirection
private int[] getXvalue(int radius) {
int[] xPoint = new int[360];
for (int i = 0; i < 360; ++i) {
double xplus = Math.cos(Math.toRadians(i+1)) * radius;
xPoint[i] = (int) Math.round(xCenter + xplus); }
return xPoint;
}
private int[] getYvalue(int radius) {
int[] yPoint = new int[360];
for (int i = 0; i < 360; ++i) {
double yPlus = Math.sin(Math.toRadians(i+1)) * radius;
yPoint[i] = (int) Math.round(yCenter - yPlus); }
return yPoint;
}
}
PS.: My computer is most likely not the cause, since it can run a lot bigger games with at least 100fps
Edit: None of the other methods, as for example the rotate() method, is causing the lag, as I have already tried the entire code with only the most essential methods and the result was the same.
Edit2: Maybe its worth noting, that the lag actually is only barely noticeable. However, for a game as small as an Asteroids is, there really shouldn't be any lag, especially if it only runs on 60 fps.
Edit3: MRE is added
I would suggest an/fps-limiting approach instead because the lag that can happen in the game gets amplified by the strict time intervals of the Timer class. After you set the frame to be visible add the following code(or something like it):
long time = System.nanoTime();
while(!gameOver) {
long nTime = System.nanoTime();
float diff = (nTime - time) * 0.000000001f;
if(diff > 1.0f / fps) {
time = nTime;
// do rendering here and multiply any speeds or accelerations by diff
}
}
I need to code my program to randomly select three cards from a deck of cards. The images are in a folder on my desktop. I then display the images of the cards. My program runs fine as far as reading from the file and then randomly picking 3 cards out of the 52. I have the program printing the 3 random cards in the output. But I can not see the images of the cards when the java window opens up on my computer. It displays a small line that just continuously repeats. So I think it is trying to display the cards but I have something wrong somewhere that is keeping the whole card(s) from displaying.
Thanks in advance for your help!
import java.awt.Graphics;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class DisplayThreeCards {
public static void main(String[] args) {
// File location
File folder = new File("//Users//macuser//Desktop//DeckOfCards");
File[] fileList;
fileList = folder.listFiles();
// Generate random card. Uses the Math.rand() function.
// The '%' operator is used to make sure the random is between 0-52.
int randomCard = (int) (Math.random() * 1000);
System.out.println(fileList[randomCard % 52].getAbsolutePath());
// Print the filename.
// Card 1
System.out.println(fileList[randomCard % 52].getName());
randomCard = (int) (Math.random() * 1000);
// Card 2
System.out.println(fileList[randomCard % 52].getName());
randomCard = (int) (Math.random() * 1000);
// Card 3
System.out.println(fileList[randomCard % 52].getName());
randomCard = (int) (Math.random() * 1000);
try {
ImageFrame frame = new ImageFrame(fileList[randomCard % 52].getAbsolutePath());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
} catch (Exception E) {
}
// Create a window for the card images to be displayed
class ImageFrame extends JFrame {
public ImageFrame(String name) {
setTitle("ImageTest");
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
ImageComponent component = new ImageComponent(name);
add(component);
}
public static final int DEFAULT_WIDTH = 300;
public static final int DEFAULT_HEIGHT = 300;
}
class ImageComponent extends JComponent {
private static final long serialVersionUID = 1L;
private Image image;
public ImageComponent(String name) {
try {
File image2 = new File(name);
image = ImageIO.read(image2);
} catch (IOException e) {
}
}
#Override
public void paintComponent(Graphics g) {
if (image == null) {
}
int imageWidth = image.getWidth(this);
int imageHeight = image.getHeight(this);
g.drawImage(image, 50, 50, this);
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);
}
}
}
}
}
}
}
I'm having trouble to find the right Layout Manager. I have some images inside a JPanel, they are all different size so I wanted to use a Flow Layout to let the manager handle them. The manager fills all the first row as possible and then warps to another line. This is all ok, but what I want is to stop at second "warp". I just want to show 2 rows of images and if then you want to see more you must click a JButton to load the others. Actually the FlowLayout keeps inserting in a third line and the images are cutted by half because the panel is not "tall" enough. Any tips?
I've already tried with Flow Layout and Mig Layout without success.
Combine a FlowLayout(outerPanel) with a GridBagLayout(innerPannel)
u can define the rows by yourself, and then u put a JScrollPane over it so it wont cut your pictures and u will still be able to see them in full size(my suggestion)
I couldn't resist trying to solve this. I had hoped to make use of FlowLayouts, but in the end, I ended up using only GridBagLayouts: One for each row of images, plus one for the entire container. I may have over-engineered in terms of flexibility, but I imagine something like this may be useful to myself or others in the future.
In essence, every time the container changes size, or images are added/removed, or any of its visual properties change, updateLayout() is called, which rebuilds all of the GridBagLayout panels from scratch. I'm sure there are ways to make this more efficient, and I'm sure it's possible to write a LayoutManager2 implementation from scatch that does the job, but this performed reasonably well for me.
import java.util.List;
import java.util.ArrayList;
import java.util.Objects;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferedImage;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class ImagePanel
extends JPanel {
private static final long serialVersionUID = 1;
/** #serial */
private final List<Icon> images = new ArrayList<>();
/** #serial */
private final List<Icon> scaledImages = new ArrayList<>();
/** #serial */
private int maxRowCount = 2;
/** #serial */
private int hgap = 6;
/** #serial */
private int vgap = 6;
/** #serial */
private int maxImageWidth = 200;
/** #serial */
private int maxImageHeight = 200;
public ImagePanel() {
setLayout(new GridBagLayout());
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent event) {
updateLayout();
}
});
}
#Override
public void addNotify() {
super.addNotify();
updateLayout();
}
#Override
public Dimension getPreferredSize() {
Rectangle screen = findGraphicsConfiguration().getBounds();
Dimension size = new Dimension();
Dimension row = new Dimension();
int rowsComputed = 0;
int gap = 0;
for (Icon image : scaledImages) {
if (row.width > 0 &&
row.width + gap + image.getIconWidth() > screen.width) {
if (++rowsComputed >= maxRowCount) {
break;
}
size.width = Math.max(size.width, row.width);
size.height += (size.height > 0 ? vgap : 0) + row.height;
row.setSize(0, 0);
gap = 0;
}
row.width += gap + image.getIconWidth();
row.height = Math.max(row.height, image.getIconHeight());
gap = hgap;
}
size.width = Math.max(size.width, row.width);
size.height += (size.height > 0 ? vgap : 0) + row.height;
return size;
}
private void updateLayout() {
int width = getWidth();
if (width == 0) {
return;
}
for (Component rowContainer : getComponents()) {
((JComponent) rowContainer).removeAll();
}
GridBagConstraints rowConstraints = new GridBagConstraints();
rowConstraints.gridwidth = GridBagConstraints.REMAINDER;
rowConstraints.weightx = 1;
rowConstraints.anchor = GridBagConstraints.FIRST_LINE_START;
int row = -1;
int rowWidth = 0;
GridBagConstraints gbc = new GridBagConstraints();
for (Icon image : scaledImages) {
JComponent rowContainer = (row >= 0 && row < getComponentCount() ?
(JComponent) getComponent(row) : null);
int gap = (rowWidth > 0 ? hgap : 0);
if (rowContainer == null ||
rowWidth + gap + image.getIconWidth() > width) {
if (++row >= maxRowCount) {
break;
}
gap = 0;
rowWidth = 0;
if (row < getComponentCount()) {
rowContainer = (JComponent) getComponent(row);
} else {
rowContainer = new JPanel(new GridBagLayout());
add(rowContainer, rowConstraints);
}
rowConstraints.insets.top = vgap;
}
gbc.insets.left = gap;
JComponent imageContainer = new JLabel(image);
rowContainer.add(imageContainer, gbc);
rowWidth += gap + image.getIconWidth();
}
for (int i = getComponentCount() - 1; i >= maxRowCount; i--) {
remove(i);
}
}
private GraphicsConfiguration findGraphicsConfiguration() {
GraphicsConfiguration config = getGraphicsConfiguration();
if (config == null) {
GraphicsEnvironment env =
GraphicsEnvironment.getLocalGraphicsEnvironment();
config = env.getDefaultScreenDevice().getDefaultConfiguration();
}
return config;
}
private Icon scale(Icon image) {
int imageWidth = image.getIconWidth();
int imageHeight = image.getIconHeight();
if (imageWidth > maxImageWidth || imageHeight > maxImageHeight) {
float scale = Math.min((float) maxImageWidth / imageWidth,
(float) maxImageHeight / imageHeight);
if (scale < 1) {
GraphicsConfiguration config = findGraphicsConfiguration();
BufferedImage scaledImage = config.createCompatibleImage(
(int) (imageWidth * scale),
(int) (imageHeight * scale));
Graphics2D g = scaledImage.createGraphics();
g.scale(scale, scale);
image.paintIcon(this, g, 0, 0);
g.dispose();
image = new ImageIcon(scaledImage);
}
}
return image;
}
public List<Icon> getImages() {
return new ArrayList<>(images);
}
public void clearImages() {
images.clear();
updateLayout();
revalidate();
}
public void addImage(Icon image) {
Objects.requireNonNull(image, "Image cannot be null");
images.add(image);
scaledImages.add(scale(image));
updateLayout();
revalidate();
}
public void removeImage(Icon image) {
int index = images.indexOf(image);
if (index >= 0) {
removeImage(index);
}
}
public void removeImage(int index) {
images.remove(index);
scaledImages.remove(index);
updateLayout();
revalidate();
}
public int getHgap() {
return hgap;
}
public void setHgap(int gap) {
if (gap < 0) {
throw new IllegalArgumentException("Gap must be at least zero");
}
int old = this.hgap;
this.hgap = gap;
if (old != gap) {
updateLayout();
revalidate();
}
firePropertyChange("hgap", old, gap);
}
public int getVgap() {
return vgap;
}
public void setVgap(int gap) {
if (gap < 0) {
throw new IllegalArgumentException("Gap must be at least zero");
}
int old = this.vgap;
this.vgap = gap;
if (old != gap) {
updateLayout();
revalidate();
}
firePropertyChange("vgap", old, gap);
}
public int getMaxRowCount() {
return maxRowCount;
}
public void setMaxRowCount(int count) {
if (count < 0) {
throw new IllegalArgumentException("Count must be at least zero");
}
int old = this.maxRowCount;
this.maxRowCount = count;
if (old != count) {
updateLayout();
revalidate();
}
firePropertyChange("maxRowCount", old, count);
}
public int getMaxImageWidth() {
return maxImageWidth;
}
private void recomputeScaledImages() {
scaledImages.clear();
for (Icon image : images) {
scaledImages.add(scale(image));
}
}
public void setMaxImageWidth(int width) {
if (width <= 0) {
throw new IllegalArgumentException("Width must be positive");
}
int old = this.maxImageWidth;
this.maxImageWidth = width;
if (old != width) {
recomputeScaledImages();
updateLayout();
revalidate();
}
firePropertyChange("maxImageWidth", old, width);
}
public int getMaxImageHeight() {
return maxImageHeight;
}
public void setMaxImageHeight(int height) {
if (height <= 0) {
throw new IllegalArgumentException("Height must be positive");
}
int old = this.maxImageHeight;
this.maxImageHeight = height;
if (old != height) {
recomputeScaledImages();
updateLayout();
revalidate();
}
firePropertyChange("maxImageHeight", old, height);
}
public static void main(final String[] args)
throws java.io.IOException {
if (args.length == 0) {
System.err.println("Usage: java " + ImagePanel.class.getName()
+ " <directory> | <url1> <url2> ...");
System.exit(2);
}
final List<java.net.URL> urls;
if (args.length == 1 && !args[0].contains(":")) {
urls = new ArrayList<>();
try (java.nio.file.DirectoryStream<java.nio.file.Path> dir =
java.nio.file.Files.newDirectoryStream(
java.nio.file.Paths.get(args[0]))) {
for (java.nio.file.Path file : dir) {
urls.add(file.toUri().toURL());
}
}
} else {
urls = new ArrayList<>(args.length);
for (String url : args) {
urls.add(new java.net.URL(url));
}
}
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ImagePanel imagePanel = new ImagePanel();
for (java.net.URL url : urls) {
imagePanel.addImage(new ImageIcon(url));
}
javax.swing.JFrame frame =
new javax.swing.JFrame("ImagePanel");
frame.setDefaultCloseOperation(
javax.swing.JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.weightx = 1;
gbc.weighty = 1;
panel.add(imagePanel, gbc);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
});
}
}
So this is our code... we´re nobs and need a bit help with getting our buttons to switch between showing hue/saturation/brigntness in height and width. Per now, our applications is only showing hue in width and saturation in height. Our buttons are not working, and we are not able to empty the view and repaint another one. Can anybody help?
package no.uib.info221.oblig1;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import com.github.imgur.ImgUr;
import com.github.imgur.api.album.AlbumRequest;
import com.github.imgur.api.album.AlbumResponse;
import com.github.imgur.api.model.ImageProperty;
public class ImgurViz extends JFrame {
private static final long serialVersionUID = 7954882289770950884L;
//private JProgressBar progressBar;
private JButton HSbutton;
private JButton BSbutton;
private JButton BHbutton;
private JPanel knappepanel;
private JPanel bildepanel;
public JLabel skjerm;
int w = 0;
int h = 1;
/**
* constructor
* klassen.
* #throws IOException
*/
public ImgurViz() throws IOException {
super(); //Calls the superclass
setupInterface(); //
fetchAndDisplayImages(); //
}
//Empties the panel when a new jlabel is called
public void emptyPanel(){
bildepanel.revalidate();
bildepanel.removeAll();
bildepanel.repaint();
}
// Creates JButtons to change the sorting of the images
public void knapper(){
knappepanel = new JPanel(); // Knappepanel = button panel
bildepanel = new JPanel(); // Imagepanel = image panel
bildepanel.setLayout(null);
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(knappepanel,BorderLayout.NORTH);
this.getContentPane().add(bildepanel,BorderLayout.CENTER);
//knappepanel.setOpaque(false);
// Knapp for HUE og SATURATION KNAPP = button
HSbutton = new JButton ("Hue og Saturation");
knappepanel.add(HSbutton);
//Knapp for BRIGHTNESS og SATURARION
BSbutton = new JButton ("Brightness og Saturation");
knappepanel.add(BSbutton);
// Knapp for BRIGHTNESS OG HUE
BHbutton = new JButton ("Brightness og Hue");
knappepanel.add(BHbutton);
// Metode for knapp for HUE og SATURATION
HSbutton.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
emptyPanel();
w = 0;
h = 1;
System.out.println("Hue: " + w + " Saturation: " + h);
}
});
// Metode for knapp for BRIGHTNESS og SATURATION
BSbutton.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
w = 2;
h = 1;
System.out.println("Brightness: " + w + " Saturation: " + h);
}
});
// Metode for knapp for BRIGHTNESS OG HUE
BHbutton.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
emptyPanel();
w = 2;
h = 0;
System.out.println("Brightness: " + w + " Hue: " + h);
}
});
this.setContentPane(knappepanel);
}
/**
* Fetches images for an album on Imgur
*
* #throws IOException
*/
public void fetchAndDisplayImages() throws IOException {
ImgUr imgUr = new ImgUr ("4ded93e63e96762");
AlbumResponse response = imgUr.call(new AlbumRequest("RJBiQ"));
List<ImageProperty> images = response.getImages();
float[] bildedata = new float[3];
int count = images.size();
for (int i = 0; i<count;i++){
BufferedImage img = ImageIO.read(new URL(images.get(i).getLinks().getOriginal()));
BufferedImage thumb = ImageIO.read(new URL(images.get(i).getLinks().getSmallSquare()));
bildedata = pictureAnalyze (img);
int width = ((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth())/2; // Henter ut bredden p brukerens skjerm
int height = ((int)Toolkit.getDefaultToolkit().getScreenSize().getHeight())/2; // Henter ut høyden p brukerens skjerm
int posW = (int)(bildedata [w] * width);
int posH = (int)(bildedata [h] * height);
skjerm = new JLabel(new ImageIcon(thumb));
skjerm.setBounds(posW, posH, width, height);
bildepanel.add(skjerm);
this.getContentPane().add(skjerm);
this.getContentPane().setLayout(null);
this.getContentPane().repaint();
this.setVisible(true);
// skjerm.addMouseListener(new MouseAdapter() {
// #Override
// public void mouseEntered(java.awt.event.MouseEvent evt) {
// //FAEN TA DEG!!
// }
// });
}
}
// RGB to HSB Finds the RGB value of each image, transformes the values to HSB and finds the average
public float[] pictureAnalyze (BufferedImage img){
float[] result = new float[3];
float h = 0f;
float s = 0f;
float b = 0f;
for (int x = 0; x < img.getWidth(); x++){
for (int y = 0; y < img.getHeight(); y++){
int c = img.getRGB(x,y);
int red = (c >> 16) & 0xff;
int green = (c >> 8) & 0xff;
int blue = (c & 0xff);
float[] hsb = Color.RGBtoHSB(red,green,blue, null);
h += hsb[0];
s += hsb[1];
b += hsb[2];
}
}
h = h/(img.getWidth()*img.getHeight());
s = s/(img.getWidth()*img.getHeight());
b = b/(img.getWidth()*img.getHeight());
result [0] = h;
result [1] = s;
result [2] = b;
return result;
}
// // Shannon entropi
// public static Double calculateShannonEntropy(List <ImageProperty> images) {
// Map<String, Integer> map = new HashMap<String, Integer>();
//
// // tel kvar instans av verdiane
// for (String sequence : images) {
// if (!map.containsKey(sequence)) {
// map.put(sequence, 0);
//
// }
// map.put(sequence, map.get(sequence) + 1);
// }
//
// //Kalkulerer entropien
//
// Double result = 0.0;
// for (String sequence : map.keySet()) {
// Double frequency = (double) map.get(sequence) / images.size();
// result -= frequency * (Math.log(frequency) / Math.log(2));
// }
//
// return result;
//
// }
/**
private void setupInterface() {
int width = (int)Toolkit.getDefaultToolkit().getScreenSize().getWidth(); // Henter ut bredden p brukerens skjerm
int height = (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight(); // Henter ut h¯yden p brukerens skjerm
this.setSize(width, height); // Setter st¯rrelsen p vinduet til  vÊre lik skjermens bredde og h¯yde
this.setExtendedState(Frame.MAXIMIZED_BOTH); // Sier fra om at vinduet skal vÊre maksimert
this.setUndecorated(true); // setter fullscreen
this.getContentPane().setBackground(Color.BLACK ); // Setter bakgrunnsfargen p innholdspanelet (contentPane) til svart
knapper();
this.setVisible(true); // Viser vinduet p skjermen
}
public static void main(String[] args) throws IOException {
ImgurViz viz = new ImgurViz(); // Oppretter et nytt ImgurViz-objekt. Dette medf¯rer at det nye objektets konstrukt¯r kj¯res
}
}
As shown in the HSV panel of JColorChooser, it's easier to display just two of the color space's three dimensions at a time. Whatever your goal, it will be easier to scale the palette using Color.getHSBColor(). These examples may offer some insight or help you prepare an sscce.