How would I refresh this panel - java

I want to make a kind of digital clock which you can activate by using enter to kind of refresh the clock display, for that I use this method:
private static void GUI(String time, int action){
JLabel textLabel = new JLabel(time);
JPanel panel = new JPanel();
JFrame enterMessage = new JFrame("Tester");
if (action == 1){
enterMessage.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
enterMessage.setSize(190, 80);
enterMessage.setVisible(true);
panel.setBackground(Color.WHITE);
panel.add(textLabel);
enterMessage.add(panel);
}else {
System.out.printf("Refresh");
panel.revalidate();
enterMessage.revalidate();
panel.repaint();
enterMessage.repaint();
}
}
}
This method gets called twice in the program code: one time to make the GUI upon opening the program and everytime an enterpress is detected to refresh it. I searched on internet how to refresh a JPanel and I found that you needed to use revalidate(); and then repaint(); but it does not refresh the time displayed by the panel. How would I refresh it?
ps:the time is passed from the main as a string and everytime an enterpress is detected gets overwritten and passed

Follow Java naming conventions. Variable names should NOT start with an upper case character.
Don't keep adding the label to the panel. Just use the setText(...) method of JLabel to change the text being displayed.
Edit:
An example of a SSCCE that shows you how to use the setText(...) method:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class TimerTime extends JPanel implements ActionListener
{
private JLabel timeLabel;
public TimerTime()
{
timeLabel = new JLabel( new Date().toString() );
add( timeLabel );
Timer timer = new Timer(1000, this);
timer.setInitialDelay(1);
timer.start();
}
#Override
public void actionPerformed(ActionEvent e)
{
//System.out.println(e.getSource());
timeLabel.setText( new Date().toString() );
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("TimerTime");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new TimerTime() );
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}

Related

Swing: JTextField inside JPanel, redraw issue

I have recently started working with Java+Swing building an UI and I currently have an issue with JTextField placed on JPanel with FlowLayout.
In my example I have a window, containing panel with button. Clicking the button adds a component derived from JPanel and containing JTextField.
The problem is that when I type in JTextField it does not get updated (does not get resized). However when I resize the window or do anything else which forces window/panel redraw, the text field being resized (just what I expect to happen automatically).
When I change base class from JPanel to JTextField it works in the way I try to achieve, but I need to have JPanel as the base class so that I can take advantages of putting child components to it.
I have checked different questions here as well as I have Googled trying to find the solution, however it did not work for me. I have tried validate/invalidate/revalidate/repaint in different combinations and for different components, as well as trying to enforce revalidation for each typed character, which does not sound as the right way for me. So far I understoon that it is something to do with Layout Managers.
Could anyone please help me with understanding how that works and what should I read about how Swing UI, layout management and redrawing is working?
Also, I would be glad if someone could help me with my particular issue with my code.
Thanks in advance!
Here is my code below:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
class TagVisual extends JPanel /*JTextField*/ {
private JTextField editField;
public TagVisual() {
FlowLayout layout = new FlowLayout();
layout.setHgap(0);
layout.setVgap(0);
setLayout(layout);
editField = new JTextField();
editField.setBackground(Color.RED);
editField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
editField.setSize(editField.getSize());
editField.revalidate();
remove(editField);
add(editField);
revalidate();
repaint();
}
});
add(editField, FlowLayout.LEFT);
}
public void place(JPanel panel) {
panel.add(this);
editField.grabFocus();
}
}
public class MainWindow {
private JPanel mainPanel;
private JButton btnPlace;
private JFrame frame;
public MainWindow(JFrame frame) {
mainPanel = new JPanel(new FlowLayout());
btnPlace = new JButton();
btnPlace.setText("Place");
mainPanel.add(btnPlace);
this.frame = frame;
btnPlace.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
TagVisual v = new TagVisual();
v.place(mainPanel);
mainPanel.revalidate();
mainPanel.repaint();
mainPanel.updateUI();
frame.revalidate();
frame.repaint();
}
});
}
public static void main(String[] args) {
JFrame frame = new JFrame("TextFieldUpdateIssue");
frame.setContentPane(new MainWindow(frame).mainPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
If i were you, i would not try to resize the textfields when the user enters some text.
I suggest you to give them a fixed size using JTextField (int columns) constructor, this will allow you to create some textfields which are "wide enough".
If you still want to make them wider when some text is entered, you can't use an ActionListener, since it will fire an event when the user presses ENTER key, not based on the text entered.
For this purpose you can register a Document Listener on your textfield's document.
You also could override getPreferredSize () method to calculate and return an appropriate size. In the example below i use a JLabel for convenience to calculate the preferred width, but you could use FontMetrics.
If you are adding multiple tags to your panel, you should also consider using a JScrollPane in order to make scrollbars appear when your panel needs more space.
See this example (i changed a bit your code because it would not compile and the general design was bad, now i think it is better, but not still good) :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class MainWindow
{
public static void main (String [] a) {
SwingUtilities.invokeLater (new Runnable () {
#Override public void run () {
try {
UIManager.setLookAndFeel (UIManager.getSystemLookAndFeelClassName ());
createAndShowGUI ();
}
catch (Exception e) {
JOptionPane.showMessageDialog (null, "An unexpected error occurred: " + e.getClass ().getSimpleName (), "Error", JOptionPane.ERROR_MESSAGE);
}
}
});
}
private static void createAndShowGUI () {
JFrame frame = new JFrame ("TextFieldUpdateIssue");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setContentPane (new MainPanel ());
frame.setExtendedState (JFrame.MAXIMIZED_BOTH);
frame.setLocationRelativeTo (null);
frame.setVisible (true);
}
}
class MainPanel extends JPanel
{
private JPanel tagsPanel;
public MainPanel () {
super (new BorderLayout (0, 10));
add (new JButton (new AbstractAction ("Add tag") {
#Override public void actionPerformed(ActionEvent e) {
addNewTag ();
}
}), BorderLayout.NORTH);
tagsPanel = new JPanel ();
tagsPanel.setLayout (new FlowLayout (FlowLayout.CENTER, 10, 0));
add (tagsPanel, BorderLayout.CENTER);
}
private void addNewTag () {
TagVisual v = new TagVisual ();
tagsPanel.add (v);
v.grabFocusOnField ();
revalidate ();
}
}
class TagVisual extends JPanel
{
private JTextField editField;
public TagVisual() {
super (new FlowLayout (FlowLayout.CENTER, 0, 0));
add (editField = createNewTextField (null), FlowLayout.LEFT);
}
private JTextField createNewTextField (String text) {
JTextField textField = new JTextField (text) {
#Override public Dimension getPreferredSize () {
Dimension d = super.getPreferredSize ();
return new Dimension (new JLabel (getText ()).getPreferredSize ().width + 10, d.height);
}
};
textField.setBackground (Color.RED);
textField.getDocument ().addDocumentListener (new DocumentListener () {
#Override public void changedUpdate (DocumentEvent e) {
revalidate ();
}
#Override public void insertUpdate (DocumentEvent e) {
revalidate ();
}
#Override public void removeUpdate (DocumentEvent e) {
revalidate ();
}
});
return textField;
}
public void grabFocusOnField () {
editField.grabFocus ();
editField.setCaretPosition (editField.getText ().length ());
}
}
Screenshot (short text):
Screenshot (Longer text):
Please review the code and note comments:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class MainWindow {
private JPanel mainPanel;
private JButton btnPlace;
public MainWindow(){
JFrame frame = new JFrame("TextFieldUpdateIssue");
//you can't use components before initializing them
btnPlace = new JButton("Button");
frame.add(btnPlace, BorderLayout.NORTH);
mainPanel = new JPanel();
frame.add(mainPanel, BorderLayout.CENTER);
btnPlace.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
TagVisual v = new TagVisual();
mainPanel.add(v); //add it to main panel
//v.place(mainPanel);
//mainPanel.revalidate();
//mainPanel.repaint();
//mainPanel.updateUI();
//frame.revalidate();
//frame.repaint();
frame.pack();
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new MainWindow();
}
}
class TagVisual extends JPanel /*JTextField*/ {
private JTextField editField;
public TagVisual() {
FlowLayout layout = new FlowLayout();
layout.setHgap(0);
layout.setVgap(0);
setLayout(layout);
editField = new JTextField();
//give it a preferred size to be used by layout manager
editField.setPreferredSize(new Dimension(150,25));
editField.setBackground(Color.RED);
editField.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//not sure what you want to do here
//not relevant to the question
}
});
add(editField, FlowLayout.LEFT);
}
}

How to make sure Swing UI is actually displayed on screen?

When I click on button another JFrame class is getting opened. The JFrame will be visible on the screen after 2 seconds but the isVisible returns true before that. I want to start timer when the JFrame actually getting displayed on the screen. How can I achieve this ? I tried to used isShowing() and isDisplayable() but it's not giving expected result.
You could use something like this:
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.*;
public class MainApp {
JFrame frame = new JFrame("Main");
JButton button = new JButton("Toggle auxiliary");
JFrame auxFrame = new JFrame("Auxiliary");
public MainApp() {
button.addActionListener(evt -> {
// Delay displaying for 2 seconds
Timer timer = new Timer(2000, event -> {
auxFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
auxFrame.setSize(320, 240);
auxFrame.setVisible(true);
});
timer.start();
auxFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowOpened(WindowEvent e) {
// Stop timer after the auxiliary frame is displayed
timer.stop();
}
});
});
frame.add(button);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setSize(320, 240);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(MainApp::new);
}
}

How to opening a new class within java

Started of with java coding for school. when i create the following code it won't work.
Please help me out.
import javax.swing.*;
import java.awt.*;
public class StartScherm extends JFrame
{
public static void main( String[] args ){
JFrame frame = new StartScherm();
frame.setSize( 800, 800 );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setTitle( "CityTours" );
JPanel Paneel = new Paneel();
frame.setContentPane( Paneel );
frame.setVisible( true );
}
}
class Paneel extends JPanel {
private JButton Eng, LoginAdmin, LoginUser;
private JTextField Text;
public Paneel(){
setLayout (null);
Eng = new JButton ("Bring me to the English version");
Eng.setBounds(250,20,300,20);
Eng.addActionListener(newEngHandler());
Text = new JTextField (" Welkom bij CityTours ");
Text.setBounds(100,80,600,600);
Text.setEditable (false);
LoginAdmin = new JButton ("Login administrator");
LoginAdmin.setBounds(100,720,200,20);
LoginUser = new JButton ("Login gebruiker");
LoginUser.setBounds(500,720,200,20);
add (Eng);
add (Text);
add (LoginAdmin);
add (LoginUser);
}
class EngHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
this.dispose();
new MainScreen().setVisible(true);
}
}
}
I'm trying to create a JButton called Eng to close the frame of StartScherm.Java and open a frame of MainScreen.Java (all in the same project)
All it does is create 3 JButtons and a JTextField, and the Eng JButton action won't work. (error: cannot find symbol)
Please help me and explain to me what i do wrong.
It is not clear from your code what is MainScreen but, let me give you an idea on how you can switch between two JFrame windows with a button click.
You need access to isVisible() and setVisible() methods of JFrame in order to hide/display a window. Since, I do not know what MainScreen is, I will use StartScherm and create two instance of it (two windows with different titles) and then switch between the two.
Declare two instances of StartScherm outside your main method in StartScherm as shown below:
public class StartScherm extends JFrame {
static JFrameCloseEvent frame1;
static JFrameCloseEvent frame2;
public static void main(String[] args) {
//your main code initializing frame1 and frame2 goes here
}
}
The reason we declare frame1 and frame2 outside main method is because we want to be able to reference them in Paneel class. The reason they are static is because we initialize them in main method and main is static that is why.
Now that we have to instances of StartScherm as frame1 and frame2 we can initialize them differently in main method of StartScherm, see below:
//already declared frame1 outside main method
frame1 = new JFrameCloseEvent();
frame1.setSize(800, 800);
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.setTitle("CityTours Default Language");
JPanel Paneel = new Paneel();
frame1.setContentPane(Paneel);
//frame1 be visible when program start
frame1.setVisible(true);
And we will will initialize the frame2 in a similiar fashion but, with different title and set its visibility to false. See below:
frame2 = new JFrameCloseEvent();
frame2.setSize(800, 800);
frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame2.setTitle("CityTours English Version");
JPanel Paneel2 = new Paneel();
frame2.setContentPane(Paneel2);
//set visibility to false because frame1 is visible at beginning
frame2.setVisible(false);
Now that we have both frame1 and frame2 initialized. We can tweak our Paneel to properly implement an ActionListener and switch visibility of the frame1 and frame2. In order to set ActionListener on a button, I prefer the following approach:
Eng = new JButton("Bring me to the English version");
Eng.setBounds(250, 20, 300, 20);
Eng.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(StartScherm.frame1.isVisible()) {
StartScherm.frame1.setVisible(false);
StartScherm.frame2.setVisible(true);
} else {
StartScherm.frame1.setVisible(true);
StartScherm.frame2.setVisible(false);
}
}
});
As you can see above, I attach the ActionListener straight to button. Since both frame1 and frame2 use Paneel hence, they will get the same button with action listener. When the button is clicked, the actionPerformed is executed which checks whether frame1 is visible or frame2. If frame1 is visible then it will set its visibility to false and set visibility of frame2 to true, else other way round.
Make above changes to your code, that is properly implement ActionListener as shown above, and make sure that your frame1 and frame2 instances are accessible in actionPerformed method.
I have modified your code to make it runnable, see below (obviously I removed references to MainScreen because, the only difference between frame1 and frame2 is title).
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class StartScherm extends JFrame {
static StartScherm frame1;
static StartScherm frame2;
public static void main(String[] args) {
frame1 = new StartScherm();
frame1.setSize(800, 800);
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.setTitle("CityTours Default Language");
JPanel Paneel = new Paneel();
frame1.setContentPane(Paneel);
frame1.setVisible(true);
frame2 = new StartScherm();
frame2.setSize(800, 800);
frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame2.setTitle("CityTours English Version");
JPanel Paneel2 = new Paneel();
frame2.setContentPane(Paneel2);
frame2.setVisible(false);
}
}
class Paneel extends JPanel {
private JButton Eng, LoginAdmin, LoginUser;
private JTextField Text;
public Paneel() {
setLayout(null);
Eng = new JButton("Bring me to the English version");
Eng.setBounds(250, 20, 300, 20);
Eng.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(StartScherm.frame1.isVisible()) {
StartScherm.frame1.setVisible(false);
StartScherm.frame2.setVisible(true);
} else {
StartScherm.frame1.setVisible(true);
StartScherm.frame2.setVisible(false);
}
}
});
Text = new JTextField(" Welkom bij CityTours ");
Text.setBounds(100, 80, 600, 600);
Text.setEditable(false);
LoginAdmin = new JButton("Login administrator");
LoginAdmin.setBounds(100, 720, 200, 20);
LoginUser = new JButton("Login gebruiker");
LoginUser.setBounds(500, 720, 200, 20);
add(Eng);
add(Text);
add(LoginAdmin);
add(LoginUser);
}
}
Eng.addActionListener(newEngHandler());
should be
Eng.addActionListener(new EngHandler());
newEngHandler() would denote a method which cannot be found new EngHandler() would denote instantiating a new class

Java Timers and TextFields

I have a panel where I have an uneditable Textfield. I want to be able to add a textField.setText(timer); sort of thing in the panel. I basically just want the JTextArea to display it like this: 0:0:0.
I've tried making Timers, TimerTasks, ActionListeners and the sort. I can't get the hang of this. Maybe it's because where I'm adding the timer? At the moment I tried adding it in a public void guiComponents() throws Exception{...}. This method holds all the properties for the panel, the frame it's in and other components.
Maybe I'm not understating the whole concept of timers. Origanlly I tried using a double-nested for loop to achieve this task, but because this has to go on while the rest of the program is running, I couldn't do that.
Don't use a JTextField for this. Use a JLabel to display text. Something like:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class TimerTime extends JFrame implements ActionListener
{
JLabel timeLabel;
public TimerTime()
{
timeLabel = new JLabel( new Date().toString() );
getContentPane().add(timeLabel, BorderLayout.NORTH);
}
public void actionPerformed(ActionEvent e)
{
timeLabel.setText( new Date().toString() );
}
public static void main(String[] args)
{
TimerTime frame = new TimerTime();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setVisible(true);
int time = 1000;
javax.swing.Timer timer = new javax.swing.Timer(time, frame);
timer.setInitialDelay(1);
timer.start();
}
}

Progress bar to run simultaneously with a function(in another class)

I have created a form on which two components are present, button and progressbar (Netbeans drag and drop).Form contains the main method from where my application starts.I have created another class as well in which i have written a function.What i want is that when i press a button the application goes into the function and the progressbar runs simultaneously with it and when that function is complete with its functionality the the progress bar shows 100% complete.Now this function can take anytime for its completion so i cannot set the max value for the progressbar.So, what to do in this case?Can anyone please provide me with a good example .
JProgressBar.setIndeterminate(true)
Since what sort of a work you are doing inside that so called "Called Function", so it's tough to say, what you want in the scenario, though you can put your lines like progressBar.setValue(someProgress); at regular intervals with it's Indeterminate State to true, and at the end of the function you can simply say that progressBar.setValue(100); and the Indeterminate State will turn to false here, so that it can show that to the end user.
Have a look at this sample program :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ProgressExample
{
public static JProgressBar progressBar;
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("Progress Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout(5, 5));
progressBar = new JProgressBar(0, 100);
progressBar.setValue(0);
JButton button = new JButton("START");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
progressBar.setIndeterminate(true);
WorkingDialog wd = new WorkingDialog();
wd.createAndDisplayDialog();
}
});
contentPane.add(progressBar, BorderLayout.PAGE_START);
contentPane.add(button, BorderLayout.PAGE_END);
frame.setContentPane(contentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new ProgressExample().createAndDisplayGUI();
}
});
}
}
class WorkingDialog extends JDialog
{
private String message = "HelloWorld";
private int count = 0;
private JTextField tfield;
private Timer timer;
private ActionListener timerAction = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
if (count == 10)
{
timer.stop();
ProgressExample.progressBar.setIndeterminate(false);
ProgressExample.progressBar.setValue(100);
ProgressExample.progressBar.setStringPainted(true);
dispose();
return;
}
tfield.setText(tfield.getText() + message.charAt(count));
count++;
}
};
public void createAndDisplayDialog()
{
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setLocationByPlatform(true);
JPanel panel = new JPanel();
tfield = new JTextField(10);
panel.add(tfield);
add(panel);
pack();
setVisible(true);
timer = new Timer(1000, timerAction);
timer.start();
}
}
So , it seems like you are write
ProgressExample.progressBar.setIndeterminate(false);
ProgressExample.progressBar.setValue(100);
ProgressExample.progressBar.setStringPainted(true);
after your while loop.
You can take a look at my answer in a previous SO question, which contains a sample using a JProgressBar which gets updates from another Thread by using a SwingWorker. Whether or not to use a SwingWorker depends a bit on your use case. If the function take some time to run you better use the SwingWorker to avoid blocking the UI.

Categories

Resources