I have following java code in my thread class:
#Override
public void run() {
JFrame window = new JFrame("Visualization POC");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while (true) {
window.setVisible(false);
Layout<Node,Edge> layout = new CircleLayout<Node, Edge>(graph);
layout.setSize(new Dimension(300, 300));
BasicVisualizationServer<Node, Edge> vv = new BasicVisualizationServer<Node, Edge>(layout);
vv.setPreferredSize(new Dimension(350, 350));
vv.getRenderContext().setVertexFillPaintTransformer(new NodeColorTransformer());
vv.getRenderContext().setEdgeDrawPaintTransformer(new EdgeColorTransformer());
window.getContentPane().add(vv);
window.pack();
window.setVisible(true);
try {
Thread.sleep(ONE_SECOND);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I want to use it to refresh state of graph visualization, but I got stuck on massive problem. When the block of code creating layout and setting content of JFrame is inside while loop it is not displayed in output window. When I place it before while, it works fine but it isn't that what I want. I run this thread via SpringUtilities.invokeLater in my main class.
I can see that the window is refresh, because it is blinking for a while.
I'm looking forward for any tips.
You invoke your code from EDT thread. Any update to the component will be painted at the end of the EDT thread. Your thread will not exit
I have modified your code little, it works fine. please replace JLabel with your jung .
final JFrame window = new JFrame("Visualization POC");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final Random ran = new Random();
while (true) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
window.setVisible(false);
JPanel panel = new JPanel();
JLabel label = new JLabel();
int nextInt = ran.nextInt(100);
label.setText("Test Label"+String.valueOf(nextInt));
System.out.println(nextInt);
panel.add(label);
window.getContentPane().removeAll();
window.getContentPane().add(panel);
window.pack();
window.setVisible(true);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Related
I am trying to write an application that get video frames, process them and then display them in JPanel as images. I use the OpenCV library to get video frames (one by one), then they are processed and after that displayed on the screen (to get the effect of playing video).
I created the GUI using Java Swing. A window application is created with the necessary buttons and a panel to display the video. After clicking "START", a method playVideo is called, which takes video frames from the selected video, modifies them and displays them in the panel. My code looks like this:
public class HelloApp {
private JFrame frame;
private JPanel panel;
final JLabel vidpanel1;
ImageIcon image;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
HelloApp window = new HelloApp();
window.frame.setVisible(true);
}
});
}
public void playVideo() throws InterruptedException{
Mat inFrame = new Mat();
VideoCapture camera = new VideoCapture();
camera.open(Config.filename);
while (true) {
if (!camera.read(inFrame))
break;
Imgproc.resize(inFrame, inFrame, new Size(Config.FRAME_WIDTH, Config.FRAME_HEIGHT), 0., 0., Imgproc.INTER_LINEAR);
... processing frame
ImageIcon image = new ImageIcon(Functions.Mat2bufferedImage(inFrame)); // option 0
vidpanel1.setIcon(image);
vidpanel1.repaint();
}
}
public HelloApp() {
frame = new JFrame("MULTIPLE-TARGET TRACKING");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);//new FlowLayout()
frame.setResizable(false);
frame.setBounds(50, 50, 800, 500);
frame.setLocation(
(3 / 4) * Toolkit.getDefaultToolkit().getScreenSize().width,
(3 / 4) * Toolkit.getDefaultToolkit().getScreenSize().height
);
frame.setVisible(true);
vidpanel1 = new JLabel();
panel = new JPanel();
panel.setBounds(11, 39, 593, 371);
panel.add(vidpanel1);
frame.getContentPane().add(panel);
JButton btnStart = new JButton("START / REPLAY");
btnStart.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
playVideo();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
});
}
}
I tried to delete the old panel and create a new one every time when button "START" is clicked, but it didn't work. Also I tried before running method playVideo to clean all the panel with methods:
panel.removeAll();
panel.repaint();
playVideo();
And to be honest I don't know what's wrong. The GUI is created, frames are taken and processed, but the panel displays only the last frame. I would be grateful for any advice :)
First of all, a proof it can actually work, somehow, with your code.
Here I read JPG images located in the resources folder, but it actually doesn't really matter.
Your code is a bit messy too. Where are you attaching the btnStart JButton to the outer panel? You need to understand how to layout components too.
You have a main JFrame, and a root JPanel which needs a layout. In this case we can opt for a BorderLayout.
panel = new JPanel(new BorderLayout());
Then we add our components.
panel.add(btnStart, BorderLayout.PAGE_START);
panel.add(vidpanel1, BorderLayout.CENTER);
Now coming to your issue, you say
The gui is created, frames are taken and processed, but panel display only the last frame
I don't know how much the "last frame" part is true, mostly because you're running an infinite - blocking - loop inside the Event Dispatch Thread, which will cause the GUI to freeze and become unresponsive.
In actionPerformed you should actually spawn a new Thread, and inside playVideo you should wrap
ImageIcon image = new ImageIcon(Functions.Mat2bufferedImage(inFrame));
vidpanel1.setIcon(image);
vidpanel1.repaint(); // Remove this
in EventQueue.invokeAndWait, such as
// Process frame
...
// Update GUI
EventQueue.invokeAndWait(() -> {
ImageIcon image = new ImageIcon(Functions.Mat2bufferedImage(inFrame));
vidpanel1.setIcon(image);
});
So I have several problems:
1) Is this code OK ? Or can it be written better ? (I will have an array with pictures in the final version)
2) When I click Next button the rectangle that I drew on first picture stays on the second one, how to clear it ? So after pressing Next button there is no rectangle on the new picture ?
3) I want to be able to auto-scroll while I drag the mouse button (while drawing the rectangle), but it's not really working...
Please help
public class SelectionExample {
static public TestPane panelek;
static public BufferedImage tempimage;
public static void main(String[] args) {
new SelectionExample();
}
public SelectionExample() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
panelek = new TestPane();
panelek.setPreferredSize(new Dimension(100, 100));
panelek.setAutoscrolls(true);
JScrollPane scrollPane = new JScrollPane(panelek);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
frame.add(scrollPane, BorderLayout.CENTER);
JButton next = new JButton("NEXT");
frame.add(next, BorderLayout.PAGE_START);
try {
tempimage = ImageIO.read(new File("D:/test/temp1.jpg"));
} catch (IOException ex) {
Logger.getLogger(SelectionExample.class.getName()).log(Level.SEVERE, null, ex);
}
next.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
try {
tempimage = ImageIO.read(new File("D:/test/temp2.jpg"));
} catch (IOException ex) {
Logger.getLogger(SelectionExample.class.getName()).log(Level.SEVERE, null, ex);
}
panelek.repaint();
}
});
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Is this code OK ? Or can it be written better ?
Don't use static variables. If you want to change the image on your panel then you need to create a setImage(...) method in your class. The method will then save the image and invoke repaint(). That is classes should be responsible for managing their properties and provide getter/setter methods.
The formatting of your code is terrible and therefore difficult to read. Use either tabs or spaces for code indentation and be consistent.
I want to be able to auto-scroll while I drag the mouse button
Read the API for the setAutoScrolls(...) method of the JComponent class. It provides code for the mouseDragged(...) method of your MouseMotionLister.
public class Pragrassbar extends JFrame implements MouseListener {
JProgressBar jb;
int i = 0, num = 0;
JButton jbt;
JLabel jl;
Pragrassbar() {
setSize(400, 400);
setLayout(new FlowLayout());
jbt = new JButton("Start");
jl = new JLabel("Click Start!");
jb = new JProgressBar(0, 2000);
jb.setValue(0);
jb.setStringPainted(true);
jbt.addMouseListener(this);
add(jbt);
add(jb);
add(jl);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void mouseClicked(MouseEvent me) {
jl.setText("downloading.....");
jbt.setEnabled(false);
try {
while (i <= 2000) {
jb.setValue(i);
jb.paintImmediately(0, 0, 200, 25);
i = i + 40;
Thread.sleep(30);
}
jl.setText("download complete");
jbt.setEnabled(true);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
Pragrassbar m = new Pragrassbar();
m.setVisible(true);
}
setText() not functioning under mouseClicked function of MouseListener interface
although it works after the while loop that i have used
The Thread.sleep() causes the Event Dispatch Thread (EDT) to sleep which means the GUI can't repaint itself until the looping code is finished executing.
Don't use Thread.sleep. Instead long running code should execute in a separate Thread so you don't block the EDT. You should probably use a SwingWorker for this.
Read the section from the Swing tutorial on Concurrency for more information and working examples on this approach.
You can also read the section on How to Use Progress Bars for the proper way to do this.
i wrote my code like below and LABEL moved correctly:
panel.setLayout(null);
JLabel label1=new JLabel("LABEL");
JLabel label2=new JLabel("0");
JButton btn1=new JButton("start");
btn1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e)
{
Thread t=new Thread()
{
public void run()
{
while(true)
{
try
{
Thread.sleep(10);
}
catch (Exception ex)
{}
label2.setText(String.valueOf(Integer.parseInt(label2.getText())+1));
label1.setLocation(label1.getX()+1, label1.getY());
}
}
};
t.start();
}
});
but when i wrote in Netbeans Jframe it didn't move!
is it possible that problem is from JFrame layout manager??
How can i solve it?
At the same problem, when i comment line A of below code changing location of jLabel2 working correctly but when both line A and B aren't comment jLabel2 never move!!
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
Thread t=new Thread()
{ public void run()
{ while(true)
{ try
{ Thread.sleep(10); }
catch (Exception ex) {}
/* line A */
jLabel1.setText(String.valueOf(Integer.parseInt(jLabel1.getText())+1));
/* line B */
jLabel2.setLocation(jLabel2.getX()+1, jLabel2.getY());
}
}
};
t.start();
}
Again
If you're animating a component, then the container that holds it needs to use a null layout. If you're not sure what layout it's using, ask it -- call getLayout() and print out the result.
Use a Swing Timer not a background thread to drive your animation. This will ensure that you make Swing calls on the Swing event thread, something that your code is not doing.
After moving your component, call revalidate() and repaint() on the container that holds it.
I have a JFrame containing various components and I would like to add a translucent grey overlay over the top while the application is initializing various things. Ideally it would prevent interaction with the underlying components and would be able to display some "Loading..." text or a spinning wheel or something similar.
Is there a simple way to do this using Java and Swing?
Take a look at JRootPane and JLayeredPane http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html#layeredpane
What you're asking about specifically sounds like a Glass Pane.
http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html#glasspane
The Glass Pane prevents interaction with underlying components and can be used to display something on top of your JFrame.
As #David said, you can use the glass pane for displaying some loading text or image above the rest of the application.
As for the grey overlay: why don't you use the built in ability to disable components as long as your application is loading? Disabled components will get grayed out automatically and cannot be interacted with by the user.
Something like this:
public class LoadingFrame extends JFrame{
JButton button;
public LoadingFrame() {
button = new JButton("ENTER");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Application entered");
}
});
setLayout(new BorderLayout());
add(button, BorderLayout.CENTER);
}
public void startLoading(){
final Component glassPane = getGlassPane();
final JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
final JLabel label = new JLabel();
panel.add(label, BorderLayout.SOUTH);
setGlassPane(panel);
panel.setVisible(true);
panel.setOpaque(false);
button.setEnabled(false);
Thread thread = new Thread(){
#Override
public void run() {
for (int i = 5; i > 0; i--) {
label.setText("Loading ... " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// loading finished
setGlassPane(glassPane);
button.setEnabled(true);
}
};
thread.start();
}
public static void main(String[] args) {
LoadingFrame frame = new LoadingFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.startLoading();
frame.setVisible(true);
}
}