JList is showing duplicates - java

I am working on a small example using Java Swing where I want to draw a sine graph on one panel and the co-ordinates of the graph in another panel. So I created a class that extends the JFrame then I created the JPanel for graph and co-ordinates. For displaying co-ordinates I am using JList. Now the problem is the co-ordinates are showing duplicate values. Here is my code:
public class MyFrame extends JFrame {
JList list;
DecimalFormat df = new DecimalFormat("#.###");
DefaultListModel model = new DefaultListModel();
private JPanel contentPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MyFrame frame = new MyFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MyFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 600, 600);
contentPane = new JPanel();
contentPane.setBorder(new LineBorder(new Color(0, 0, 0)));
setContentPane(contentPane);
contentPane.setLayout(new GridLayout(1, 2, 0, 0));
JPanel panel = new MyGraph();
panel.setBorder(new LineBorder(new Color(0, 0, 0)));
contentPane.add(panel);
list = new JList(model);
list.setVisibleRowCount(4);
JPanel panel_1 = new JPanel();
panel_1.setBorder(new LineBorder(new Color(0, 0, 0)));
panel_1.setLayout(new BoxLayout(panel_1, BoxLayout.Y_AXIS));
JLabel lblNewLabel_1 = new JLabel("X - Y");
panel_1.add(lblNewLabel_1);
JScrollPane slistScroller = new JScrollPane(list);
panel_1.add(slistScroller);
contentPane.add(panel_1);
}
class MyGraph extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
int xBase = 10;
int top = 100;
int yScale = 10;
int xAxis = 360;
int yBase = top + yScale;
g.drawLine(xBase, top, xBase, top + 2 * yScale);
g.drawLine(xBase, yBase, xBase + xAxis, yBase);
g.setColor(Color.red);
int x2=0, y2=0;
int x1 = xBase + 0;
int y1 = yBase - (int) (10*Math.sin(0) * yScale);
int i;
for (i = 0; i < 10; i++) {
x2 = xBase + i;
y2 = yBase - (int) (10*Math.sin(i) * yScale);
g.drawLine(x1, y1, x2, y2);
x1 = x2;
y1 = y2;
df = new DecimalFormat("#.###");
model.addElement(i +" -- " + df.format(10*Math.sin(i)));
}
model.addElement("------END----------");
}
}
}
Here is the output of my program:
As per my program, I have a for loop from angles 0 to 10 and I am adding the values to DefaultListModel model which is added to JList list.
Can someone please help me where I am doing mistake in this code?
Also even when I have this line list.setVisibleRowCount(4); , I was expecting only 4 records displayed to the user with a scroll-bar, but as per the output image it is not working like that.

paintComponent may be any number of times, for any number of reasons, try resizing the frame and see what happens.
Your paint method should focus on doing just that, painting.
You need to change the process so that the paintComponent becomes depend on the model, not the other way round.
Take a look at Painting in AWT and Swing for more details about painting in Swing.
You may also want to consider using a ListCellRender to render the data in the model in the JList, this way, you could more easily share the model and it's data.
See Writing a Custom Cell Renderer for more details

Related

Java Swing button creates a dupe on the panel below it

We have this assignment where we make a GUI window which sets a panel's color based on RGB-Alpha values. I got it mostly working, but when I click the change color button, it duplicates (I'm not sure if its only visual bug) a clicked state of itself under it. It's not visible if alpha is 255 because it's fully opaque, but if it's transparent, the visual glitch thing is visible.
Screenshots of Window/Frame: https://imgur.com/a/Vf1Hb2B
This is my current code:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.JOptionPane;
public class ColorCalc implements ActionListener {
//Containers
private JFrame f;
private JPanel colorPanel;
//Components
private JLabel l1,l2,l3,l4;
private JTextField redTf,greenTf,blueTf,alphaTf;
private JButton bCompute,bClear;
public ColorCalc()
{
//Containers
f = new JFrame("My Color Calculator");
f.setPreferredSize(new Dimension(400, 250));//Set Frame Size
colorPanel = new JPanel();
colorPanel.setPreferredSize(new Dimension(300, 200));//Set Panel Size
//Components
l1 = new JLabel("Red:");
l2 = new JLabel("Green:");
l3 = new JLabel("Blue:");
l4 = new JLabel("Alpha:");
redTf = new JTextField("0", 3);
greenTf = new JTextField("0", 3);
blueTf = new JTextField("0", 3);
alphaTf = new JTextField("0", 3);
bCompute = new JButton("Compute");
bClear = new JButton("Clear");
//Action Listeners
bCompute.addActionListener(this);
bClear.addActionListener(this);
}
public void startApp()
{
//Labels Panel
JPanel lPanel = new JPanel();
lPanel.setLayout(new GridLayout(5,1));
lPanel.add(l1);
lPanel.add(l2);
lPanel.add(l3);
lPanel.add(l4);
lPanel.add(bCompute);
//Text Fields Panel
JPanel tfPanel = new JPanel();
tfPanel.setLayout(new GridLayout(5,1));
tfPanel.add(redTf);
tfPanel.add(greenTf);
tfPanel.add(blueTf);
tfPanel.add(alphaTf);
tfPanel.add(bClear);
//Labels + TextFields Panel
JPanel inputPanel = new JPanel();
inputPanel.setLayout(new GridLayout(1,2));
inputPanel.add(lPanel);
inputPanel.add(tfPanel);
//Add all panels to Frame
f.setLayout(new GridLayout(2,1));
f.add(inputPanel);
f.add(colorPanel);
f.setLocationRelativeTo(null);
f.pack();
f.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == bCompute)
{
//Set Default Values
int red = 255;
int green = 255;
int blue = 255;
int alpha = 255;
try
{
//Get Values and Parse to Integer
red = Integer.parseInt(redTf.getText());
green = Integer.parseInt(greenTf.getText());
blue = Integer.parseInt(blueTf.getText());
alpha = Integer.parseInt(alphaTf.getText());
} catch (NumberFormatException nfe)//If Parsing failed due to invalid types
{
red = 255; green = 255; blue = 255; alpha = 255; //Set values to white
JOptionPane.showMessageDialog(null, "Invalid Inputs (RGB,Alpha values 0-255)");
}
if(red < 256 && green < 256 && blue < 256 && alpha < 256)//Max Value: 255
{
if(red > -1 && green > -1 && blue > -1 && alpha > -1)//Min Value: 0
colorPanel.setBackground(new Color(red, green, blue, alpha));
else
JOptionPane.showMessageDialog(null, "Invalid Inputs (RGB,Alpha values 0-255)");
}
else
JOptionPane.showMessageDialog(null, "Invalid Inputs (RGB,Alpha values 0-255)");
}
else if(e.getSource() == bClear)
{
//Set all values to 0 and set panel to white
redTf.setText("0");
greenTf.setText("0");
blueTf.setText("0");
alphaTf.setText("0");
colorPanel.setBackground(Color.WHITE);
}
}
public static void main(String[] args)
{
ColorCalc colCalc = new ColorCalc();
colCalc.startApp();
}
}
Call the method f.repaint(); at the end of the actionPerformed() method
See more info here

JTextField not editable with JFrame as parent, JWindow making method unpaintable

I have the following code
private JFrame frame = (JFrame) SwingUtilities.getWindowAncestor(this);
private JWindow hsWindow = new JWindow(frame);
hsWindow.setPreferredSize(new Dimension(400, 200));
JButton btnSave = new JButton("Save");
JButton btnCancel = new JButton("Cancel");
JLabel lblName = new JLabel("Enter your name: ");
JTextField txtName = new JTextField();
hsWindow.add(btnSave);
hsWindow.add(btnCancel);
hsWindow.add(lblName);
hsWindow.add(txtName);
hsWindow.setVisible(true);
hsWindow.setFocusable(true);
hsWindow.setLocationRelativeTo(frame);
btnSave.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
hsName = txtName.getText();
saveHighScores();
hsWindow.setVisible(false);
hsWindow.setFocusable(false);
txtName.setText("");
setHighScores();
gameOver(g);
}
});
Can someone tell me why the JTextField is not editable?
The field itself is there, but I cannot type in it.
Also, when I call my method gameOver(g) without the JWindow appearing, everything is fine. However, if I have the JWindow appear and call it after pushing the button, my gameOver method is not properly painted.
Why is that?
Here is the important parts of the gameOver method
private void gameOver(Graphics g){
int z = 25;
score = dots - 3; //The amount of apples collected = your score
String msg = "Game Over";
String scoreS = "Final Score : " + score; //Displaying score
Font small = new Font("Helvetica", Font.BOLD, 14);
Font smallnb = new Font("Helvetica", Font.PLAIN, 12);
FontMetrics metric = getFontMetrics(small); //FontMetrics is easier to use to position text
g.setColor(Color.white);
g.setFont(small);
//Centers and Draws the Messages
g.drawString(msg, (WIDTH - metric.stringWidth(msg)) / 2, HEIGHT / 2);
g.drawString(scoreS, (WIDTH - metric.stringWidth(scoreS)) / 2, ((HEIGHT / 2) - 30));
//Drawing High Scores
metric = getFontMetrics(smallnb);
g.setFont(smallnb);
g.setColor(Color.red);
for(String line : str.split("\n")){
g.drawString(line, (WIDTH - metric.stringWidth(str)) - 110, z +=
g.getFontMetrics().getHeight());
}

FlowLayout not going to new line

I'm trying to add a variable number of JPanels (each one containst 2 Label) inside another JPanel using the FlowLayout.
When there's too many panels added instead of going to the new row they disappear out of the border
I've tried many types of Layouts, setting sizes, maximussizes but nothing changes.
public class AlbumView extends javax.swing.JFrame
{
private Album A;
public AlbumView()
{
initComponents();
A = new Album();
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
int w = this.getSize().width;
int h = this.getSize().height;
int x = (dim.width-w)/2;
int y = (dim.height-h)/2;
this.setLocation(x, y);
pnlCategorie.setLayout(new FlowLayout(FlowLayout.TRAILING, 10, 10));
/*
Insert of many elements in the Album
*/
aggiornaAlbum();
}
public void aggiornaAlbum()
{
for(int i = 0; i < A.getDim(); i++)
{
Categoria c = A.getCategoria(i);
JPanel pnl = new JPanel();
pnl.setName(c.getNome());
JLabel lb1, lb2;
ImageIcon img = new ImageIcon(c.getPhoto(0).getImg(95, 95)); //da cambiare lo 0 con un numero casuale tra le foto disponibili
lb1 = new JLabel(img, JLabel.CENTER);
lb2 = new JLabel(c.getNome(), JLabel.CENTER);
pnl.setLayout(new BoxLayout(pnl, BoxLayout.Y_AXIS));
pnl.setBorder(BorderFactory.createLineBorder(Color.black));
pnl.add(lb1);
pnl.add(lb2);
//pnl.revalidate();
//pnl.repaint();
pnlCategorie.add(pnl);
}
//ADDED AFTER COMMENT, NOTHING CHANGED (but probably it's because i didn't get exaclty what to do
pnlCategorie.revalidate();
pnlCategorie.repaint();
}
pnlCategorie is created using NetBeans swing.
I expect that after the number of jpanels that fits the bigger jPanel the next one goes to a new line
Example of what is appearing (I'm using some exaple image, don't judge) :

placing items into a panel with gridlayout

Hey everyone I am trying to draw a checkerboard in Java with GUI. I have created a square class for the squares of the game board.
Square Class:
import javax.swing.*;
import java.awt.*;
public class Square extends JPanel {
private int width = 80;
private int height = 80;
private int x,y;
private Color color;
public Square(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
public void paint(Graphics graphics){
//setSize(new Dimension(width,height));
graphics.setColor(color);
graphics.drawRect(x,y, width,height);
graphics.fillRect(x,y,width,height);
}
}
Basically I wanted to create a panel with grid layout of 8 by 8. Then add square objects grid layout panel. I want the first row to contain red,black,red,black,red,black,red,black squares and the second row to contain black,red,black,red,black,red,black,red squares.
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setPreferredSize(new Dimension(600,600));
JPanel panel = new JPanel(new GridLayout(8,8));
panel.setLayout(new GridLayout(8, 8));
panel.setBackground(Color.green);
Square redsqr1 = new Square(0,0, Color.RED);
Square blksqr1 = new Square(0,0, Color.BLACK);
Square redsqr2 = new Square(0,0, Color.RED);
Square blksqr2 = new Square(0,0, Color.BLACK);
Square redsqr3 = new Square(0,0, Color.RED);
Square blksqr3 = new Square(0,0, Color.BLACK);
Square redsqr4 = new Square(0,0, Color.RED);
Square blksqr4 = new Square(0,0, Color.BLACK);
Square redsqr5 = new Square(0,0, Color.RED);
Square blksqr5 = new Square(0,0, Color.BLACK);
Square redsqr6 = new Square(0,0, Color.RED);
Square blksqr6 = new Square(0,0, Color.BLACK);
Square redsqr7 = new Square(0,0, Color.RED);
Square blksqr7 = new Square(0,0, Color.BLACK);
Square redsqr8 = new Square(0,0, Color.RED);
Square blksqr8 = new Square(0,0, Color.BLACK);
panel.add(redsqr1);
panel.add(blksqr1);
panel.add(redsqr2);
panel.add(blksqr2);
panel.add(redsqr3);
panel.add(blksqr3);
panel.add(redsqr4);
panel.add(blksqr4);
panel.add(blksqr5);
panel.add(redsqr5);
panel.add(blksqr6);
panel.add(redsqr6);
panel.add(blksqr7);
panel.add(redsqr7);
panel.add(blksqr8);
panel.add(redsqr8);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
When I run the program I get the output
Just curious as to why the output is placed in 2 columns with big space between each square. How would i get them to stay side byside on one row to have the first row to containing red,black,red,black,red,black,red,black squares and the second row to containing black,red,black,red,black,red,black,red squares.
Thanks in advance for your help!
It's because you didn't add all the 64 needed squares to the layout. So the layout cells would be stretched to fill all the space. As the result the output would be messy. Moreover, it's a good idea to set the horizontal and vertical gaps to 0. One more hint is by calling JFrame#add it will add the component to the contentPane and there is no need to get the contentPane to add something to a JFrame. In addition an intermediary JPanel is not needed between the underlying JFrame and the Squares.
Also I changed the main method a little to reduce the hardships of creating and adding the Squares to the output frame:
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.setPreferredSize(new Dimension(600,600));
frame.setLayout(new GridLayout(8, 8, 0, 0));
frame.getContentPane().setBackground(Color.green);
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
frame.add(new Square(0, 0, (i+j)%2==0 ? Color.RED : Color.BLACK));
}
}
frame.pack();
frame.setVisible(true);
}
Hope this would help.

How to make a JPanel into a BufferedImage Java

I have a half-working paint/turtle graphics program but I am having a few issues.
I am going to need to save the image that is drawn at some point - I know I need to use a BufferedImage but how do I go about this? I have attached a little bit of my code below.
In short I have a JFrame with a text field and a white JPanel below it. When commands are typed in by the user lines are drawing through another class and appear on the JPanel. I know I won't be able to save them off the JPanel to an image but have no understanding of how to implement a buffered image and what i would/wouldn't need to change.
Please be kind, I am new to programming and haven't finished some parts of my code yet.
Thanks in advance
public class Turtle2 extends JFrame implements ActionListener, KeyListener{
JMenuBar menuBar;
JMenu help, file;
JPanel panel, panel2;
JMenuItem newO, load, save, exitO, about;
JTextField text;
int savecounter = 0, newcounter = 1, part2I = 0;
int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
int trigger = 1, turnleftconstant = 0, turnrightconstant =0, direction =0;
int col = 0;
public Turtle2() {
setLayout(new FlowLayout());
setSize(1000, 1000);
setTitle("Graphic");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//menu bar
//sets up general look of window
panel = new JPanel();
panel.setBackground(Color.darkGray);
//implements box layout
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
//sets up drawing area
panel2 = new JPanel();
panel2.setPreferredSize(new Dimension(500, 500));;
panel2.setBackground(Color.WHITE);
panel2.setBorder(BorderFactory.createLineBorder(Color.darkGray, 3));
//starting point on drawing area co-ordinates
x1 = 15; x2 = 15; y1 = 230; y2 =230;
//starting point implemented
LinePen first = new LinePen(x1, y1, x2, y2, col);
panel2.add(first);
//sets up user input text box
text = new JTextField(30);
//add action listener to text box - ready for input and details responses
text.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
//retrieves user input
String actions = text.getText();
first.setVisible(true);
//commands from text
//add the command line textfeild to the interface
panel.add(text);
//uses border layout to set the layout of the interface
getContentPane().add(BorderLayout.NORTH, panel);
getContentPane().add(BorderLayout.CENTER, panel2);
//set the size of the interface
setSize(600,600);
//ensure the interface is visible
setVisible(true);
}
I would keep an array of all your lines, then iterate through them, and then use img.createGraphics() to draw your lines and other graphics.

Categories