Java AWT/Swing Updating JPanel Continously Not Working - java

I am trying to make a program that populates a JPanel with GridLayout with the contents of a HashMap that contains String keys to JButton values. Because the size of the HashMap may change, I can't just use setText() for each button. So far I've called .removeAll() to remove the JPanel of all buttons, then I loop through the HashMap to repopulate the JPanel. I then call revalidate() on the JPanel and repaint() on the JFrame.
Current Code:
public class GUI implements Runnable, ActionListener
{
private ToDo td;
JFrame frame;
Thread t=null;
int fontsize = 18;
private Container contentPane;
private JPanel topPane;
private JButton main;
private JButton add;
private JButton settings;
private JPanel centerPane;
private JScrollPane centerScroll;
private JPanel scrollable;
private HashMap<String, JButton> items;
public static void main(String[] args) {
new GUI();
}
public GUI(){
td = new ToDo();
frame = new JFrame();
t = new Thread(this);
t.start();
frame.setMinimumSize(new Dimension(480, 640));
frame.setLayout(null);
frame.setVisible(true);
contentPane = frame.getContentPane();
contentPane.setLayout(new BorderLayout());
topPane = new JPanel();
topPane.setLayout(new GridLayout(1, 3));
topPane.setPreferredSize(new Dimension(480, 40));
main = new JButton("View Tasks");
main.setFont(new Font("Sans Serif", Font.PLAIN, fontsize));
add = new JButton("Add Task");
add.setFont(new Font("Sans Serif", Font.PLAIN, fontsize));
settings = new JButton("Settings");
settings.setFont(new Font("Sans Serif", Font.PLAIN, fontsize));
topPane.add(main);
topPane.add(add);
topPane.add(settings);
contentPane.add(topPane, BorderLayout.NORTH);
centerPane = new JPanel();
centerPane.setPreferredSize(new Dimension(480, 600));
items = new HashMap<>();
HashMap<String, Assignment> assignments = td.getAssignments();
scrollable = new JPanel();
scrollable.setLayout(new GridLayout(assignments.size(), 1));
centerScroll = new JScrollPane(scrollable);
for(String key: assignments.keySet()){
Assignment a = assignments.get(key);
JButton button = new JButton(a.getTitle() + " | " + a.getDetails() + " | " + a.getClassification().getCls() + " | " + a.getStatus().getStatus());
button.addActionListener(this);
items.put(key, button);
scrollable.add(button);
}
centerPane.add(centerScroll);
contentPane.add(centerPane, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
public void update(int i){
HashMap<String, Assignment> assignments = td.getAssignments();
scrollable.removeAll();
scrollable.setLayout(new GridLayout(assignments.size(), 1));
for(String key: assignments.keySet()){
Assignment a = assignments.get(key);
JButton button = new JButton(Integer.toString(i));
button.addActionListener(this);
items.put(key, button);
scrollable.add(button);
}
scrollable.revalidate();
frame.repaint();
}
#Override
public void run(){
int counter = 0;
try {
while (true) {
update(counter);
t.sleep( 1000 ); // interval given in milliseconds
counter++;
}
}
catch (Exception e) {
System.out.println();
}
}
#Override
public void actionPerformed(ActionEvent e){
for(String s: items.keySet()){
if(items.get(s) == e.getSource()){
EventMenu em = new EventMenu(td, s);
}
}
}
}
The problem is that the buttons are not updating. I expect that the JPanel should be constantly repopulating with updated JButtons with different text, but it seems that the program hangs and doesn't update.
I tried making a simpler example which I modified from here, with different results:
public class DigitalWatch implements Runnable{
JFrame f;
JPanel p;
Thread t=null;
int hours=0, minutes=0, seconds=0;
String timeString = "";
JButton b;
DigitalWatch(){
f=new JFrame();
p = new JPanel();
t = new Thread(this);
t.start();
b=new JButton();
b.setBounds(100,100,100,50);
p.add(b);
f.add(p);
f.setSize(300,400);
f.setLayout(null);
f.setVisible(true);
}
public void run() {
try {
while (true) {
Calendar cal = Calendar.getInstance();
hours = cal.get( Calendar.HOUR_OF_DAY );
if ( hours > 12 ) hours -= 12;
minutes = cal.get( Calendar.MINUTE );
seconds = cal.get( Calendar.SECOND );
SimpleDateFormat formatter = new SimpleDateFormat("hh:mm:ss");
Date date = cal.getTime();
timeString = formatter.format( date );
p.removeAll();
b=new JButton(timeString);
b.setBounds(100,100,100,50);
p.add(b);
f.add(p);
p.revalidate();
f.repaint();
//printTime();
t.sleep( 1000 ); // interval given in milliseconds
}
}
catch (Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) {
new DigitalWatch();
}
}
This snippet fails to draw anything, unlike the first which at least draws the objects created in the constructor.
How can I make a list or grid JPanel update procedurally and in real time and populate buttons? I know I could change the text of each button every time, but the number of buttons may change at any time.
Full code here.

you are violating Swing's single thread rule - you are not supposed to do any UI related stuff outside Swing's event dispatch thread.
Read up on it here and here.
Below is a working example. Not sure why they chose to use a button to show the time though. :-)
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.Timer;
public class DigitalWatch extends JFrame {
private DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM);
public DigitalWatch() {
JButton btn = new JButton(getCurrentTime());
this.getContentPane().setLayout(new FlowLayout());
this.getContentPane().add(btn);
this.setPreferredSize(new Dimension(200, 150));
this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null); // center it on the screen
new Timer(500, e -> btn.setText(getCurrentTime())).start();
}
private String getCurrentTime() {
return formatter.format(LocalTime.now());
}
public static void main(String[] args) {
new DigitalWatch().setVisible(true);
}
}

Related

How can I make graphics moving when I press start button and stop when I press stop button.(Java)

I am working on my first college project. I just start coding. I am making a washing machine for this project.
How can I make my graphics rotate when pressed the start button and stop when I pressed the stop button? Also, I have a countdown timer, once it times out, my graphics will stop rotating as well. (They are in different packages).
Here is my code(Main, first package)
package Main;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import Timer.*;
public class WashingMachine extends JPanel implements ActionListener{
JFrame frame = new JFrame("Washing Machine");
JLabel label_numCloth = new JLabel("Number of Clothes");
JTextField num_tf = new JTextField("",10);
JButton com_bt = new JButton("Compute");
JButton start_bt = new JButton("Start");
JButton stop_bt = new JButton("Stop");
JLabel label_cost = new JLabel("Cost: ");
JLabel label_price = new JLabel("1 Kg = 4 Baht");
JPanel panel_num = new JPanel();
JPanel panel_cost = new JPanel();
JPanel panel_r = new JPanel();
JPanel panel_l = new JPanel();
JPanel panel_start_stop = new JPanel();
static double cost;
WashingMachine(){
panel_num.setLayout(new GridLayout(3,1));
panel_num.add(label_numCloth);
panel_num.add(num_tf);
panel_num.add(com_bt);
panel_cost.setLayout(new GridLayout(2,1));
panel_cost.add(label_cost);
panel_cost.add(label_price);
panel_start_stop.setLayout(new GridLayout(1,2));
panel_start_stop.add(start_bt);
panel_start_stop.add(stop_bt);
panel_l.add(panel_start_stop);
panel_r.setLayout(new BorderLayout());
panel_r.add(panel_num,BorderLayout.NORTH);
panel_r.add(panel_cost,BorderLayout.CENTER);
frame.add(this);
setLayout(new BorderLayout());
frame.add(panel_r,BorderLayout.EAST);
frame.add(panel_l,BorderLayout.WEST);
frame.setBackground(Color.BLACK);
frame.setSize(250,250);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
label_price.setForeground(Color.red);
com_bt.addActionListener(this);
start_bt.addActionListener(this);
stop_bt.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
//Calculate price
double cloth = Double.parseDouble(num_tf.getText());
cost = cloth*4;
label_cost.setText("Cost: " + cost + " " + "Baht");
if(e.getSource() == start_bt) {
repaint();
Simulation sim = new Simulation();
Countdown cout_d = new Countdown();
if(e.getSource() == start_bt) {
repaint();
}
}
}
}
Here is my code (Simulation for washing machine,second package)
package Timer;
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class Simulation extends JPanel implements ActionListener{
JFrame frame = new JFrame("Simulation and Timer");
Timer timer = new Timer(500, this);
int startAngle = 0;
int shift =5;
public Simulation(){
timer.start();
frame.add(this);
frame.setSize(500,500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
g.fillOval(87,90,275,275);
g.setColor(new Color(0,255,255));
g.fillOval( 100,100 ,250,250 );
g.setColor(Color.white);
g.fillOval(275,120,20,20);
}
public void actionPerformed(ActionEvent e){
}
}
package Timer;
import java.awt.Font;
import java.awt.event.*;
import javax.swing.*;
import java.text.DecimalFormat;
import java.awt.*;
public class Countdown {
JFrame frame = new JFrame("Countdown Clock");
JLabel counter_label = new JLabel("");
Timer timer;
private int second = 0;
private int minute = 40;
String ddSecond;
String ddMinute;
DecimalFormat dFormat = new DecimalFormat("00");
Font font = new Font("Arial",Font.BOLD,20);
public static void main(String[] args) {
new Countdown();
}
public Countdown() {
frame.setSize(300,300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
counter_label.setBounds(120, 100,50 ,50 );
counter_label.setHorizontalAlignment(JLabel.CENTER);
counter_label.setFont(font);
frame.setBackground(Color.black);
frame.add(counter_label);
frame.setVisible(true);
counter_label.setText("40:00");
countdownTimer();
timer.start();
}
public void countdownTimer() {
timer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
second--;
ddSecond = dFormat.format(second);
ddMinute = dFormat.format(minute);
counter_label.setText(ddMinute + ":" + ddSecond);
if(second==-1) {
second = 59;
minute--;
ddSecond = dFormat.format(second);
ddMinute = dFormat.format(minute);
counter_label.setText(ddMinute + ":" + ddSecond);
}
if(minute==0 && second==0 ) {
timer.stop();
}
}
});
}
}

How to change (add or subtract) the value of a JLabel?

I wish to add 100 EUR to a JLabel (500 EUR) with a JButton (***). Since I cannot add nor subtract an int value from a String, I don't know what to do.
JButton button;
MyFrame(){
button = new JButton();
button.setBounds(200, 400, 250, 100);
button.addActionListener(e -> );
button.setText("***");
JLabel amount = new JLabel("500 EUR");
amount.setBounds(35, 315, 500, 100);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setSize(1200, 850);
frame.add(button);
frame.add(amount);
frame.setLayout(null);
frame.setVisible(true);
}
GUI
How to change (add or subtract) the value of a JLabel?
... Since I cannot add nor subtract an int value from a String, I don't know what to do.
This is thinking about the problem in a slightly wrong way. The number of Euros should be held separately as an int value. When an action is performed, increment the value and set it to the string with a suffix of " EUR".
Here is a complete (ready to run) example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class EuroCounter {
private JComponent ui = null;
int euros = 1000;
String suffix = " EUR";
JLabel amount = new JLabel(euros + suffix, JLabel.CENTER);
EuroCounter() {
initUI();
}
public final void initUI() {
if (ui != null) {
return;
}
ui = new JPanel(new BorderLayout(4, 4));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
JButton button;
button = new JButton("+");
button.setMargin(new Insets(20, 40, 20, 40));
ActionListener incrementListener = (ActionEvent e) -> {
amount.setText((euros+=100) + suffix);
};
button.addActionListener(incrementListener);
JPanel leftAlign = new JPanel(new FlowLayout(FlowLayout.LEADING));
leftAlign.add(button);
ui.add(leftAlign, BorderLayout.PAGE_START);
amount.setBorder(new EmptyBorder(30, 150, 30, 150));
amount.setFont(amount.getFont().deriveFont(50f));
ui.add(amount, BorderLayout.CENTER);
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
EuroCounter o = new EuroCounter();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}

is it possible to close JOptionPane.showMessageDialog(buttonPanel," ") with timer?if it's possible pls tell me how(the program code is down)

import javax.swing.*; // Graphics import java.awt.Color; // Graphics Colors
import java.awt.event.ActionListener; // Events
import java.awt.event.ActionEvent; // Events
public class ButtonDemo_Extended implements ActionListener {
// Definition of global values and items that are part of the GUI.
int redScoreAmount = 0;
int blueScoreAmount = 0;
JPanel titlePanel, scorePanel, buttonPanel;
JLabel redLabel, blueLabel, redScore, blueScore;
JButton redButton, blueButton, resetButton;
public JPanel createContentPane() {
// We create a bottom JPanel to place everything on.
JPanel totalGUI = new JPanel();
totalGUI.setLayout(null);
// Creation of a Panel to contain the title labels
titlePanel = new JPanel();
titlePanel.setLayout(null);
titlePanel.setLocation(10, 10);
titlePanel.setSize(250, 30);
totalGUI.add(titlePanel);
redLabel = new JLabel("Red Team");
redLabel.setLocation(0, 0);
redLabel.setSize(120, 30);
redLabel.setHorizontalAlignment(0);
redLabel.setForeground(Color.red);
titlePanel.add(redLabel);
blueLabel = new JLabel("Blue Team");
blueLabel.setLocation(130, 0);
blueLabel.setSize(120, 30);
blueLabel.setHorizontalAlignment(0);
blueLabel.setForeground(Color.blue);
titlePanel.add(blueLabel);
// Creation of a Panel to contain the score labels.
scorePanel = new JPanel();
scorePanel.setLayout(null);
scorePanel.setLocation(10, 40);
scorePanel.setSize(260, 30);
totalGUI.add(scorePanel);
redScore = new JLabel("" + redScoreAmount);
redScore.setLocation(0, 0);
redScore.setSize(120, 30);
redScore.setHorizontalAlignment(0);
scorePanel.add(redScore);
blueScore = new JLabel("" + blueScoreAmount);
blueScore.setLocation(130, 0);
blueScore.setSize(120, 30);
blueScore.setHorizontalAlignment(0);
scorePanel.add(blueScore);
// Creation of a Panel to contain all the JButtons.
buttonPanel = new JPanel();
buttonPanel.setLayout(null);
buttonPanel.setLocation(10, 80);
buttonPanel.setSize(260, 70);
totalGUI.add(buttonPanel);
// We create a button and manipulate it using the syntax we have
// used before. Now each button has an ActionListener which posts
// its action out when the button is pressed.
redButton = new JButton("Red Score!");
redButton.setLocation(0, 0);
redButton.setSize(120, 30);
redButton.addActionListener(this);
buttonPanel.add(redButton);
blueButton = new JButton("Blue Score!");
blueButton.setLocation(130, 0);
blueButton.setSize(120, 30);
blueButton.addActionListener(this);
buttonPanel.add(blueButton);
resetButton = new JButton("Reset Score");
resetButton.setLocation(0, 40);
resetButton.setSize(250, 30);
resetButton.addActionListener(this);
buttonPanel.add(resetButton);
return totalGUI;
}
// This is the new ActionPerformed Method.
// It catches any events with an ActionListener attached.
// Using an if statement, we can determine which button was pressed
// and change the appropriate values in our GUI.
public void actionPerformed(ActionEvent e) {
if (e.getSource() == redButton) {
redScoreAmount = redScoreAmount + 1;
redScore.setText("" + redScoreAmount);
JOptionPane.showMessageDialog(buttonPanel, "GOOOOOOOOOOOL");
} else if (e.getSource() == blueButton) {
blueScoreAmount = blueScoreAmount + 1;
blueScore.setText("" + blueScoreAmount);
JOptionPane.showMessageDialog(buttonPanel, "GOOOOOOOOOOOL");
} else if (e.getSource() == resetButton) {
redScoreAmount = 0;
blueScoreAmount = 0;
redScore.setText("" + redScoreAmount);
blueScore.setText("" + blueScoreAmount);
}
}
private static void createAndShowGUI() { // For this Class Onlyyyyyyyyyyyy .
JFrame.setDefaultLookAndFeelDecorated(true); // Style Of Frame
JFrame frame = new JFrame("[=] JButton Scores! [=]");
//Create and set up the content pane.
ButtonDemo_Extended demo = new ButtonDemo_Extended();
frame.setContentPane(demo.createContentPane());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(280, 190);
frame.setVisible(true);
}
public static void main(String[] args) {
createAndShowGUI();
} }
this might be one way to do it:
`
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.Timer;
public class AutoCloseJOption {
private static final int TIME_VISIBLE = 3000;
public static void main(String[] args) {
final JFrame frame1 = new JFrame("My App");
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.setSize(100, 100);
frame1.setLocation(100, 100);
JButton button = new JButton("My Button");
frame1.getContentPane().add(button);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane pane = new JOptionPane("Message", JOptionPane.INFORMATION_MESSAGE);
JDialog dialog = pane.createDialog(null, "Title");
dialog.setModal(false);
dialog.setVisible(true);
new Timer(TIME_VISIBLE, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dialog.setVisible(false);
}
}).start();
}
});
frame1.setVisible(true);
}
}`
I hope this helps you

JTextArea - How to set text at a specified offset?

I want to set some text at a specified offset in my JTextArea. Let's say I have already in my edit "aaa bbb" and I want to overwrite "bbb" with "house", how can I do that in Java?
You could use replaceRange()
public void replaceRange(String str,
int start,
int end)
Replaces text from the indicated start to end position with the new text specified. Does nothing if the model is null. Simply does a delete if the new string is null or empty.
This method is thread safe, although most Swing methods are not. Please see Threads and Swing for more information.
You need to take a look at three methods setSelectionStart(...), setSelectionEnd(...) and replaceSelection(...).
Here is a small sample program to help your cause :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TextAreaSelection
{
private JTextField replaceTextField;
private JTextField startIndexField;
private JTextField endIndexField;
private void createAndDisplayGUI()
{
final JFrame frame = new JFrame("JTextArea Selection");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(true);
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout(5, 5));
contentPane.setOpaque(true);
final JTextArea tarea = new JTextArea(10, 10);
tarea.setText("aaa bbb");
final JButton updateButton = new JButton("UPDATE TEXT");
updateButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
//tarea.setSelectionStart(4);
//tarea.setSelectionEnd(7);
//tarea.replaceSelection("house");
int selection = JOptionPane.showConfirmDialog(null, getPanel());
if (selection == JOptionPane.OK_OPTION)
{
if (replaceTextField.getDocument().getLength() > 0
&& startIndexField.getDocument().getLength() > 0
&& endIndexField.getDocument().getLength() > 0)
{
String text = replaceTextField.getText().trim();
int start = Integer.parseInt(startIndexField.getText().trim());
int end = Integer.parseInt(endIndexField.getText().trim());
tarea.replaceRange(text, start, end);
}
}
}
});
contentPane.add(tarea, BorderLayout.CENTER);
contentPane.add(updateButton, BorderLayout.PAGE_END);
frame.getContentPane().add(contentPane);
frame.pack();
frame.setVisible(true);
}
private JPanel getPanel()
{
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(0, 2, 2, 2));
JLabel replaceLabel = new JLabel("Enter new String : "
, JLabel.CENTER);
replaceTextField = new JTextField(10);
JLabel startIndexLabel = new JLabel("Enter Start Index : "
, JLabel.CENTER);
startIndexField = new JTextField(10);
JLabel endIndexLabel = new JLabel("Enter End Index : ");
endIndexField = new JTextField(10);
panel.add(replaceLabel);
panel.add(replaceTextField);
panel.add(startIndexLabel);
panel.add(startIndexField);
panel.add(endIndexLabel);
panel.add(endIndexField);
return panel;
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new TextAreaSelection().createAndDisplayGUI();
}
});
}
}

Adding multiple JPanels to a JFrame in real time

I am writing a tool take performs a task on text file. The task takes some time to perform so I made a panel that displays the file name and the progress in percentage.
The user may run the task on one or on several files, so I need to display a panel for each file. The problem is that the panels are not being added. I am updating my code to be self contained as suggested below:
package sscce.jpanel;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
public class FProgressDisplay extends JFrame {
private final static Logger LOGGER = Logger.getLogger(FProgressDisplay.class.getName());
private List<PanelTaskProgress> tasks;
JTextArea txtLog;
JButton btnAbort;
JButton btnClose;
public static void main(String[] args) {
try {
FProgressDisplay frame = new FProgressDisplay();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
for(int i = 0; i < 10; i++) {
frame.addTask(i, "Task"+i);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed to initialize application.");
}
}
/**
* Create the frame.
*/
public FProgressDisplay() {
setTitle("Mask tool - Progress");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
getContentPane().setLayout(null);
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
JPanel panel = new JPanel();
getContentPane().add(panel);
btnAbort = new JButton("Abort");
panel.add(btnAbort);
btnClose = new JButton("Close");
panel.add(btnClose);
txtLog = new JTextArea();
txtLog.setLineWrap(true);
getContentPane().add(txtLog);
tasks = new ArrayList<PanelTaskProgress>();
}
public void addTask(long id, String fileName) {
PanelTaskProgress newTaskPanel = new PanelTaskProgress(id, fileName);
tasks.add(newTaskPanel);
getContentPane().add(newTaskPanel);
validate();
repaint();
LOGGER.info("Added new panel");
}
public class PanelTaskProgress extends JPanel {
private static final long serialVersionUID = 1L;
JLabel lblTaskDescription;
JLabel lblProgress;
private long id;
/**
* Create the panel.
*/
public PanelTaskProgress(long id, String fileName) {
try {
setLayout(null);
lblTaskDescription = new JLabel(id + " " + fileName);
//lblTaskDescription.setBounds(10, 11, 632, 14);
add(lblTaskDescription);
lblProgress = new JLabel("0%");
lblProgress.setHorizontalAlignment(SwingConstants.CENTER);
//lblProgress.setBounds(664, 11, 51, 14);
add(lblProgress);
LOGGER.info("Created new panel; Id: " + id + "; File: " + fileName);
} catch (Exception e) {
LOGGER.severe("Error creating new panel; " + e.getMessage());
}
}
}
}
Call validate() then repaint().
This is a hacked version of your SSCCE. Not sure what the final requirement is, but I added a button that allows addition of new tasks after the the GUI is visible. Seems the repaint() call is not needed, so I edited it out.
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.util.logging.Logger;
public class FProgressDisplay extends JFrame {
private final static Logger LOGGER = Logger.getLogger(FProgressDisplay.class.getName());
private List<PanelTaskProgress> tasks;
JTextArea txtLog;
JButton btnNew;
JButton btnAbort;
JButton btnClose;
static int i;
JPanel taskPanel;
public static void main(String[] args) {
try {
FProgressDisplay frame = new FProgressDisplay();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed to initialize application.");
}
}
/**
* Create the frame.
*/
public FProgressDisplay() {
setTitle("Mask tool - Progress");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// should be done AFTER components are added
//pack();
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
taskPanel = new JPanel();
taskPanel.setLayout(new BoxLayout(taskPanel, BoxLayout.Y_AXIS));
JPanel panel = new JPanel();
getContentPane().add(panel);
btnNew = new JButton("New");
panel.add(btnNew);
btnNew.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
addTask(++i, "Task " + i);
}
});
btnAbort = new JButton("Abort");
panel.add(btnAbort);
btnClose = new JButton("Close");
panel.add(btnClose);
txtLog = new JTextArea();
txtLog.setLineWrap(true);
getContentPane().add(txtLog);
tasks = new ArrayList<PanelTaskProgress>();
JScrollPane scrollPane = new JScrollPane(taskPanel);
getContentPane().add(scrollPane);
for(i = 0; i < 10; i++) {
addTask(i, "Task"+i);
}
pack();
}
public void addTask(long id, String fileName) {
PanelTaskProgress newTaskPanel = new PanelTaskProgress(id, fileName);
tasks.add(newTaskPanel);
taskPanel.add(newTaskPanel);
validate();
//repaint();
LOGGER.info("Added new panel");
}
public class PanelTaskProgress extends JPanel {
private static final long serialVersionUID = 1L;
JLabel lblTaskDescription;
JLabel lblProgress;
private long id;
/**
* Create the panel.
*/
public PanelTaskProgress(long id, String fileName) {
try {
//setLayout(null);
lblTaskDescription = new JLabel(id + " " + fileName);
//lblTaskDescription.setPreferredSize(new Dimension(632, 14));
add(lblTaskDescription);
lblProgress = new JLabel("0%");
lblProgress.setHorizontalAlignment(SwingConstants.CENTER);
//lblProgress.setBounds(664, 11, 51, 14);
add(lblProgress);
LOGGER.info("Created new panel; Id: " + id + "; File: " + fileName);
} catch (Exception e) {
LOGGER.severe("Error creating new panel; " + e.getMessage());
}
}
}
}
You can try to remove setLayout(null); from PanelTaskProgress.
JPanel has FlowLayout by default and every panel have two component which you align horizontal center.
Two things:
First, your panels are empty because you call setLayout(null); in your PanelTaskProgressconstructor. Call setLayout(new FlowLayout()); instead and you'll see their contents.
Second, and more interestingly: Your main method is running in the main thread, not the event dispatch thread. When you call setVisible() on the frame, the EDT starts doing things. At a random time shortly after, you start changing the layout, again not from the EDT. This is bound to create problems. You have to create and modify the layout on the event dispatch thread.
Wrap your main method in
EventQueue.invokeLater(new Runnable() {
public void run() {
....
}
});
All Swing programs should do this.

Categories

Resources