I want to update jpanel in clients GUIs from the value I get from server continuously. But I can't see anything on the window.I can see the client frame if I set only one time but I need something like
while( get data from server != null){
//update the jpanel
// I tried
frame.panel.setValue(data from server)
frame.repaint()
//and this one too
frame.remove(old panel)
frame.add(new JCustomPanel(with new value))
frame.repaint()
}
I can't share my code because my teacher prohibited it but I can't solve either.Please help me :c
You need to do two things. First of all you need to create another thread, that will work with data independently from the main thread. Secondly, you need to use SwingUtilities.invokeLater method. This is a full example, that shows how it works. It changes label every second (Thread.sleep is used for delay in this example, don't use it in your real code).
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
public class NewMain {
// JFrame
static JFrame frame;
// JLabel
static JLabel label;
// Main class
public static void main(String[] args) {
frame = new JFrame("panel");
label = new JLabel();
// Creating a panel to add label
JPanel panel = new JPanel();
panel.add(label);
// Adding panel to frame
frame.add(panel);
// Setting the size of frame
frame.setSize(300, 300);
frame.show();
doLoop();
}
private static void doLoop() {
Thread newThread = new Thread(() -> {
while (true) {
SwingUtilities.invokeLater(() -> {
label.setText(new java.util.Date().toString());
});
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(NewMain.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
newThread.start();
}
}
Related
I wrote a simple Timer class, and I want to set the frame layout to Border layout and put timer at north. I'm new to layouts, can anyone help me with how to do this?
import java.awt.*;
import javax.swing.*;
public class TimerTest extends JFrame{
JButton timerLabel = null;
public TimerTest()
{
this.setTitle("Timer Test");
Container c = this.getContentPane();
c.setLayout(new FlowLayout());
timerLabel = new JButton("0");
timerLabel.setEnabled(false);
c.add(timerLabel);
this.setSize(150,150);
this.setVisible(true);
int k = 100;
while(true)
{
timerLabel.setText(k+" seconds left");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
k--;
}
}
public static void main(String[] args) {
new TimerTest();
}
}
Container c = this.getContentPane(); // has border layout by DEFAULT
c.setLayout(new FlowLayout()); // but now it has flow layout!
// ..
c.add(timerLabel);
So change that to:
Container c = this.getContentPane(); // has border layout by DEFAULT
// ..
c.add(timerLabel, BorderLayout.PAGE_START); // PAGE_START is AKA 'NORTH'
Other tips:
Don't extend JFrame, just use an instance of one.
JButton timerLabel is a confusing name, it should be JButton timerButton
this.setTitle("Timer Test"); could be written super("Timer Test"); or if using a standard (not extended) frame .. JFrame frame = new JFrame("Timer Test");
this.setSize(150,150); That size is just a guess. It would better be this.pack();
while(true) .. Thread.sleep(1000); Don't block the EDT (Event Dispatch Thread). The GUI will 'freeze' when that happens. See Concurrency in Swing for details and the fix.
public static void main(String[] args) { new TimerTest(); } Swing & AWT based GUIs should be created & updated on the EDT.
I am working on a simple Swing program that places one label on the frame, sleeps for one second, and then places another label on the frame as follows:
import javax.swing.*;
import java.util.concurrent.*;
public class SubmitLabelManipulationTask {
public static void main(String[] args) throws Exception {
JFrame frame = new JFrame("Hello Swing");
final JLabel label = new JLabel("A Label");
frame.add(label);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 100);
frame.setVisible(true);
TimeUnit.SECONDS.sleep(1);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
label.setText("Hey! This is Different!");
}
});
}
}
However, I cannot see the first label on the screen before the sleep. The screen is blank while sleeping. Afterwards, I see the original label for a split second and immediately afterwards the final label of "Hey! This is Different!" is on the screen. Why doesn't the original label appear on the JFrame?
It is much better and safer to use a Swing Timer in place of your sleep code, since the call to sleep risks being done on the event thread and this can put the entire GUI to sleep -- not what you want. You also want to take care to make sure that your GUI does in fact start on the Swing event thread. For example
import javax.swing.*;
import java.util.concurrent.*;
public class SubmitLabelManipulationTask {
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Hello Swing");
final JLabel label = new JLabel("A Label", SwingConstants.CENTER);
frame.add(label);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 100);
frame.setVisible(true);
Timer timer = new Timer(1000, e -> {
label.setText("Try this instead");
});
timer.setRepeats(false);
timer.start();
});
}
}
The code written by you is working perfectly fine without any issue on my machine..
import javax.swing.*;
import java.util.concurrent.*;
public class SubmitLabelManipulationTask {
public static void main(String[] args) throws Exception {
JFrame frame = new JFrame("Hello Swing");
final JLabel label = new JLabel("A Label");
frame.add(label);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 100);
frame.setVisible(true);
TimeUnit.SECONDS.sleep(1);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
label.setText("Hey! This is Different!");
}
});
}
}
Matt's comment that the sleep is happening while the GUI is loading fixed the problem for me. Turns out that although the JFrame loads immediately, loading the other components takes around a second. So by the time the label is done correctly, the sleep is subsequently done and the label is switched almost immediately after. Changing the sleep (or the Timer) to over a second allows me to see the original label there for a little longer before it switches.
I want to animate a JFrame to become half-size when i press a button in my programme. I think the easiest way is putting the current bounds of JFrame into a timer and decrease bounds 1 by 1 when the timer running.But when I declare a new timer in netbeans IDE it will looks like this.
Timer t = new Timer(5,new ActionListener() {
public void actionPerformed(ActionEvent e) {
//inside this I want to get my Jframe's bounds like this
// int width = this.getWidth();---------here,"this" means the Jframe
}
}
});
But the problem is in here "this" not refering to JFrame.And also I cant even create a new object of my JFrame.Because it will give me another window.Can anyone help me solve this problem ?.
Try
int width = Foo.this.getWidth();
where Foo subclasses JFrame.
I want to animate a JFrame to become half-size when i press a button in my programme
So when you click the button you have access to the button. Then you can use:
SwingUtilities.windowForComponent( theButton );
to get a reference to the frame.
So now when you create the ActionListener for the Timer you can pass in the Window as an argument for the ActionListener.
Edit:
The suggestion by mre is simple and straight forward and easy to use in many cases (and probably the better solution in this case).
My suggestion is a little more complicated but it was introducing you to the SwingUtilities method which will eventually allow you to write more reusable code that could potentially be used by any frame or dialog you might create.
A simple example would be something like:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class AnimationSSCCE extends JPanel
{
public AnimationSSCCE()
{
JButton button = new JButton("Start Animation");
button.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
JButton button = (JButton)e.getSource();
WindowAnimation wa = new WindowAnimation(
SwingUtilities.windowForComponent(button) );
}
});
add( button );
}
class WindowAnimation implements ActionListener
{
private Window window;
private Timer timer;
public WindowAnimation(Window window)
{
this.window = window;
timer = new Timer(20, this);
timer.start();
}
#Override
public void actionPerformed(ActionEvent e)
{
window.setSize(window.getWidth() - 5, window.getHeight() - 5);
// System.out.println( window.getBounds() );
}
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("AnimationSSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new AnimationSSCCE() );
frame.setSize(500, 400);
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Of course you would want to stop the timer when the winow reaches a certain minimum size. I'll leave that code up to you.
I'm using Container.getComponents() to get an array of Components stored inside the Container. I'm then modifying one of these Components (which happens to be a JLabel), but the changes are not showing on the GUI.
So I'm thinking maybe the method creates new instances of each Component which prevents me from making changes to the original component?
Here's my code:
Component[] components = source.getComponents();
if(components.length >= 2) {
if(components[1] instanceof JLabel) {
JLabel htmlArea = (JLabel) components[1];
htmlArea.setText("<html>new changes here</html>");
htmlArea.revalidate();
}
}
It is either another problem outside of the code, or you are doing this from the wrong thread.
Any changes on Swing components should be done in the event dispatch thread. Often is it most easy to surround the changing code with EventQueue.invokeLater(...) (or SwingUtilities.invokeLater, this is the same).
And make sure your component is actually visible on the screen.
There is no need to revalidate() or repaint() anything (unless you are doing something really strange)!
Where is your SSCCE that demonstrates your problem???
It works fine for me:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class TabbedPaneLabel extends JFrame
{
JTabbedPane tabbedPane;
public TabbedPaneLabel()
{
tabbedPane = new JTabbedPane();
add(tabbedPane);
tabbedPane.addTab("First", createPanel("<html>label with text</html>"));
tabbedPane.addTab("Second", createPanel("another label"));
JButton remove = new JButton("Change Label on first tab");
add(remove, BorderLayout.SOUTH);
remove.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
Component[] components = tabbedPane.getComponents();
JPanel panel = (JPanel)components[0];
JLabel label = (JLabel)panel.getComponent(0);
String date = new Date().toString();
label.setText("<html>" + date + "</html>");
}
});
}
private JPanel createPanel(String text)
{
JPanel panel = new JPanel();
panel.add( new JLabel(text) );
return panel;
}
public static void main(String args[])
{
TabbedPaneLabel frame = new TabbedPaneLabel();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.setSize(300, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
I have a JFrame and JPanel full of Jsomethings with an actionlistener. When the user clicks an object I want to open another JFrame. Here is what I did:
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == rejectionbutton){
RejectApp ra = new RejectApp();
ra.main(null);
}
}
(RejectApp calls a new JFrame.) So another JFrame opens on the screen with more options. It works OK (so far), but I want to know is this standard? I mean calling the main method like this?
Another question is, without using a cardlayout (which I don't want to use), is the best way to handle multiple panels, by doing this sort of thing?
I would change a few things. First off, usually an application has one JFrame and then if it needs to show another window does so as a modal or non-modal dialog such as can be obtained with a JDialog or JOptionPane. Having said that, it's even more common to have one JFrame and swap "views" in the JFrame -- swap contentPanes or other large panels via a CardLayout as this would mimic the behavior of many gui programs we all currently use.
Personally, I also try to gear my GUI creation towards creating a JPanel or JComponent rather than towards creating a top-level window. This way if I want to display the GUI as a stand alone app, a dialog, or an applet I can pop it into the contentPane of a JFrame or JDialog or JApplet respectively, or if as an inner panel of a more complex GUI, then insert it there, or in an application with a swapping view, then as a card in a CardLayout as noted above. The bottom line is I feel that this structure gives you the developer a lot more options in how you can use this GUI.
Also, I would avoid calling another class's main as you're doing (assuming this is the public static void main method) as you lose all benefits of OOPs. You also seem to be trying to call a static method in a non-static way (assuming I understand your program structure correctly).
For your second question, it begs a question of my own: why do you not want to use CardLayout?
edit: an example of what I meant is as follows:
import java.awt.Dimension;
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class SwingEg {
private static void createAndShowUI() {
JFrame frame = new JFrame("Main JFrame");
frame.getContentPane().add(new MainGUI().getMainPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class MainGUI {
private static final Dimension MAIN_PANEL_SIZE = new Dimension(450, 300);
private JPanel mainPanel = new JPanel();
private JDialog modalDialog;
private JDialog nonModalDialog;
public MainGUI() {
JButton openModalDialogBtn = new JButton("Open Modal Dialog Window");
openModalDialogBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
openModalDialogBtnActionPerformed(e);
}
});
JButton openNonModalDialogBtn = new JButton("Open Non-Modal Dialog Window");
openNonModalDialogBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
openNonModalDialogBtnActionPerformed(e);
}
});
mainPanel.setPreferredSize(MAIN_PANEL_SIZE);
mainPanel.add(openModalDialogBtn);
mainPanel.add(openNonModalDialogBtn);
}
private void openModalDialogBtnActionPerformed(ActionEvent e) {
if (modalDialog == null) {
Window topWindow = SwingUtilities.getWindowAncestor(mainPanel);
modalDialog = new JDialog(topWindow, "Modal Dialog", ModalityType.APPLICATION_MODAL);
modalDialog.getContentPane().add(new DialogPanel().getMainPanel());
modalDialog.pack();
modalDialog.setLocationRelativeTo(topWindow);
modalDialog.setVisible(true);
} else {
modalDialog.setVisible(true);
}
}
private void openNonModalDialogBtnActionPerformed(ActionEvent e) {
if (nonModalDialog == null) {
Window topWindow = SwingUtilities.getWindowAncestor(mainPanel);
nonModalDialog = new JDialog(topWindow, "Non-Modal Dialog", ModalityType.MODELESS);
nonModalDialog.getContentPane().add(new DialogPanel().getMainPanel());
nonModalDialog.pack();
nonModalDialog.setLocationRelativeTo(topWindow);
nonModalDialog.setVisible(true);
} else {
nonModalDialog.setVisible(true);
}
}
public JPanel getMainPanel() {
return mainPanel;
}
}
class DialogPanel {
private static final Dimension DIALOG_SIZE = new Dimension(300, 200);
private JPanel dialogPanel = new JPanel();
public DialogPanel() {
dialogPanel.add(new JLabel("Hello from a dialog", SwingConstants.CENTER));
dialogPanel.setPreferredSize(DIALOG_SIZE);
}
public JPanel getMainPanel() {
return dialogPanel;
}
}
I would rather make a new instance of JFrame or a subclass, or call a new method who makes a new JFrame:
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == rejectionbutton){
JFrame frame = new JFrame("New Frame");
//or
makeNewFrame();
}
}
Another simple Layout-Manager is the BorderLayout, it´s the default Layout-Manager of the JFrame class.
new YourJFrameNameHere().setVisible(true);
Replace YourJFrameNameHere with the JFrame name.
Simple, no?