more efficient layout than Box - java

I've got some very old code which uses a Box to list some information. I create it like so:
Box patterns = Box.createVerticalBox();
Very (very) often, new items are added and old items are removed eg:
label = new JLabel("xyz");
patterns.add(label);
and later
patterns.remove(label);
whenever something is added ore removed I have to have it repaint, so I call:
patterns.revalidate();
patterns.repaint();
Problem is, since this happens very often it chokes up the UI. I think I need a better implementation in order to make it more efficient.
I know I could maintain a list of the active items in the background and then intermittently update the actual UI (batch update) but...
Can someone suggest a more efficient alternative approach?

Why don't you just use a JList and implement a cell renderer?
Or more flexibility with a JTable and implement a table cell renderer (returns a Component instead)?

Based on this example, the following code loafs doing 16 labels at 10 Hz.
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
/** #see https://stackoverflow.com/questions/6605554 */
public class ImageLabelPanel extends Box implements ActionListener {
private static final int N = 16;
private final List<JLabel> list = new ArrayList<JLabel>();
private final Timer timer = new Timer(100, this);
ImageLabelPanel() {
super(BoxLayout.Y_AXIS);
BufferedImage bi = null;
try {
bi = ImageIO.read(new File("image.jpg"));
} catch (IOException e) {
e.printStackTrace(System.err);
}
for (int r = 0; r < N; r++) {
int w = bi.getWidth();
int h = bi.getHeight() / N;
BufferedImage b = bi.getSubimage(0, r * h, w, h);
list.add(new JLabel(new ImageIcon(b)));
}
createPane();
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setVisible(true);
timer.start();
}
private void createPane() {
this.removeAll();
for (JLabel label : list) {
add(label);
}
this.revalidate();
}
#Override
public void actionPerformed(ActionEvent e) {
Collections.shuffle(list);
createPane();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ImageLabelPanel();
}
});
}
}

Related

I added a gif to my JLabel but it only plays once and doesn't continue, how do i fix it?

JLabel two = new JLabel();
ImageIcon jaina= new ImageIcon("images/jaina.gif");
two.setBounds(0,0,300,300);
two.setIcon(jaina);
then i added the Label to my panel, it plays only once
If your gif is not set to loop, the correct solution is to modify the gif to have it loop.
Out of curiosity I mocked up this example. What if I want to animate a gif independent of its animation settings.
import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.FileImageInputStream;
import java.util.List;
import java.util.ArrayList;
import java.io.File;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.EventQueue;
public class GifLabel{
public static void startGui( List<ImageIcon> imgs){
JFrame frame = new JFrame("animated gif");
JLabel label = new JLabel( );
frame.add(label);
label.setIcon(imgs.get(0));
Timer t = new Timer( 30, new ActionListener(){
int i = 0;
#Override
public void actionPerformed( ActionEvent evt ){
label.setIcon ( imgs.get(i) );
i = (i+1)%imgs.size();
}
});
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
t.start();
}
public static void main(String[] args) throws Exception{
ImageReader reader = ImageIO.getImageReadersBySuffix("GIF").next();
reader.setInput( new FileImageInputStream( new File("images/jaina.gif")));
int n = reader.getNumImages( true );
List<ImageIcon> imgs = new ArrayList<>();
for(int i = 0; i<n; i++){
imgs.add( new ImageIcon(reader.read(i)) );
}
EventQueue.invokeLater( ()->{
startGui(imgs);
});
}
}
This is way more fragile than just making sure the GIF is the correct format. Also way more code, considering the original new ImageIcon("..."); handles everything.

How to get the Color pane from JColorChooser and use it in my own window?

I am new to Java and Java swing.
I need to extract only the color pane and get the color from that pane in my own window.
Basically, I want to remove other unnecessary components in the default ColorPanel.
I am successful in removing the other panels and sliders. But not further.
JColorChooser
It's difficult and requires some AWT/Swing hacks (like Robot class), but possible. I would not advise you to use this code, but if it's required...
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import javax.swing.JColorChooser;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
/**
* <code>ChooserTryout</code>.
*/
public class ChooserTryout {
public static void main(String[] args) {
try {
Robot robot = new Robot();
SwingUtilities.invokeLater(() -> new ChooserTryout().startUI(robot));
} catch (AWTException e) {
e.printStackTrace();
}
}
public void startUI(Robot robot) {
JFrame frm = new JFrame("Color test");
JColorChooser chooser = new JColorChooser();
JLabel label = new JLabel("Here is your actual color");
label.setOpaque(true);
List<JComponent> comps =
getAllChildrenOfClass(chooser, JComponent.class, c -> c.getClass().getName().contains("DiagramComponent"));
JComponent c = comps.get(3);
c.setPreferredSize(new Dimension(300, 300));
c.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
Point p = c.getLocationOnScreen();
p.translate(e.getX(), e.getY());
Color color = robot.getPixelColor(p.x, p.y);
System.out.println("You've clicked color: " + color);
label.setForeground(color);
};
});
frm.add(c);
frm.add(label, BorderLayout.SOUTH);
frm.pack();
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.setLocationRelativeTo(null);
frm.setVisible(true);
}
/**
* Searches for all children of the given component which are instances of the given class and satisfies the given condition.
*
* #param aRoot start object for search. May not be null.
* #param aClass class to search. May not be null.
* #param condition condition to be satisfied. May not be null.
* #param <E> class of component.
* #return list of all children of the given component which are instances of the given class. Never null.
*/
public static <E> List<E> getAllChildrenOfClass(Container aRoot, Class<E> aClass, Predicate<E> condition) {
final List<E> result = new ArrayList<>();
final Component[] children = aRoot.getComponents();
for (final Component c : children) {
if (aClass.isInstance(c) && condition.test(aClass.cast(c))) {
result.add(aClass.cast(c));
}
if (c instanceof Container) {
result.addAll(getAllChildrenOfClass((Container) c, aClass, condition));
}
}
return result;
}
}

Rendering Swing component smoothly every 500 millisecond

I am facing rendering problem when I call paintComponent() every 500 millisecond to show updated charts. I have around 30 barcharts created by using JFreeChart on Panel.
Rendering with error and
How can I solve this problem?
private void ShowGraphs() {
FirstChart.removeAll();
SecondChart.removeAll();
ThirdChart.removeAll();
FirstChart.add(Label1);
SecondChart.add(Label2);
ThirdChart.add(Label3);
ChartUpdate(P1,FirstChart);
ChartUpdate(P2,SecondChart);
ChartUpdate(P3,ThirdChart);
//FirstChart, SecondChart, ThirdChart is JPanels
//Tabb is JTabbedPane
paintComponents(Tabb.getGraphics());
}
This code is called every 500 milliseconds and ChartUpdate(MyObject, Panel) is chart building function on Panel using MyObject's info.
Don't replace the view component. Instead, update the corresponding model and the listening view will update itself in response. In the example below, each ChartPanel returned by createPane() has a Swing Timer that updates its XYSeries every 500 ms.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/**
* #see http://stackoverflow.com/a/38512314/230513
* #see http://stackoverflow.com/a/15715096/230513
* #see http://stackoverflow.com/a/11949899/230513
*/
public class Test {
private static final int N = 128;
private static final Random random = new Random();
private int n = 1;
private void display() {
JFrame f = new JFrame("TabChart");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel p = new JPanel(new GridLayout(0, 1));
for (int i = 0; i < 3; i++) {
p.add(createPane());
}
f.add(p, BorderLayout.CENTER);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private ChartPanel createPane() {
final XYSeries series = new XYSeries("Data");
for (int i = 0; i < random.nextInt(N) + N / 2; i++) {
series.add(i, random.nextGaussian());
}
XYSeriesCollection dataset = new XYSeriesCollection(series);
new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
series.add(series.getItemCount(), random.nextGaussian());
}
}).start();
JFreeChart chart = ChartFactory.createXYLineChart("Test", "Domain",
"Range", dataset, PlotOrientation.VERTICAL, false, false, false);
return new ChartPanel(chart) {
#Override
public Dimension getPreferredSize() {
return new Dimension(480, 240);
}
};
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
}

How can I highlight a MapMarkerDot in Openstreetmap?

I used code from http://svn.openstreetmap.org/applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/Demo.java to get a map up and running for my swing application.
I added a few MapMarkerDot to indicate some points in my map and used how can i get the mouse click position from my JMapViewer world map to identify whether a point has been selected but how can I actually show that a particular MapMarkerDot has been selected? I want to add some kind of border similar to http://bikes.oobrien.com/london/#zoom=14&lon=-0.1155&lat=51.4992 but so far I have not seen successful.
Any suggestions/ references are well appreciated. Thanks!
The MapMarkerDot parent implementation of paint() in MapMarkerCircle ignores the Stroke specified in Style, but you can extend MapMarkerCircle to use a larger radius and render anything at all. In the example below, the Update button listener shows how to alter a custom marker's background color dynamically.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import org.openstreetmap.gui.jmapviewer.Coordinate;
import org.openstreetmap.gui.jmapviewer.JMapViewer;
import org.openstreetmap.gui.jmapviewer.MapMarkerCircle;
import org.openstreetmap.gui.jmapviewer.MapMarkerDot;
import org.openstreetmap.gui.jmapviewer.Style;
/**
* #see http://stackoverflow.com/a/33857113/230513
*/
public class London {
private static final Random r = new Random();
private void display() {
JFrame f = new JFrame("London");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMapViewer map = new JMapViewer() {
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
};
Coordinate london = new Coordinate(51.5072, -0.1275);
map.setDisplayPosition(london, 16);
MyMarker dot = new MyMarker("", london);
map.addMapMarker(dot);
map.addMapMarker(new MapMarkerDot("London", london));
f.add(map);
f.add(new JButton(new AbstractAction("Update") {
#Override
public void actionPerformed(ActionEvent e) {
Style style = dot.getStyle();
style.setBackColor(Color.getHSBColor(r.nextFloat(), 1f, 1f));
style.setColor(Color.red);
map.repaint();
}
}), BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static class MyMarker extends MapMarkerCircle {
public MyMarker(String name, Coordinate coord) {
super(null, name, coord, 12, STYLE.FIXED, getDefaultStyle());
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new London()::display);
}
}

'Highgui cannot be resolved', JavaCV, Eclipse

I'm trying to set up face detection with JavaCV. I've got working code with cvLoadImage but when I try to load an image via Highgui.imread there's an error: 'Highgui cannot be resolved' and 'Highgui' has red wavy underlining. For some reason Eclipse cannot deal properly with imported com.googlecode.javacv.cpp.opencv_highgui or ...?
Problem here:
CvMat myImg = Highgui.imread(myFileName);
Full code:
import java.awt.EventQueue;
import java.awt.Insets;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import com.googlecode.javacv.cpp.opencv_core.CvMemStorage;
import com.googlecode.javacv.cpp.opencv_core.CvRect;
import com.googlecode.javacv.cpp.opencv_core.CvScalar;
import com.googlecode.javacv.cpp.opencv_core.CvSeq;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
import com.googlecode.javacv.cpp.opencv_objdetect.CvHaarClassifierCascade;
import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_highgui.*;
import static com.googlecode.javacv.cpp.opencv_objdetect.*;
import java.awt.Button;
import java.io.File;
import javax.swing.SwingConstants;
import javax.swing.JLabel;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import com.googlecode.javacv.cpp.opencv_core.CvMat;
import com.googlecode.javacv.cpp.opencv_highgui;
//import opencv_highgui;
public class Form1 {
static private final String newline = "\n";
JButton openButton, saveButton;
JTextArea log;
JFileChooser fc;
String myFileName = "";
//Load haar classifier XML file
public static final String XML_FILE =
"resources/!--master--haarcascade_frontalface_alt_tree.xml";
private JFrame frame;
//Detect for face using classifier XML file
public static void detect(IplImage src){
//Define classifier
CvHaarClassifierCascade cascade = new CvHaarClassifierCascade(cvLoad(XML_FILE));
CvMemStorage storage = CvMemStorage.create();
//Detect objects
CvSeq sign = cvHaarDetectObjects(
src,
cascade,
storage,
1.1,
3,
0);
cvClearMemStorage(storage);
int total_Faces = sign.total();
//Draw rectangles around detected objects
for(int i = 0; i < total_Faces; i++){
CvRect r = new CvRect(cvGetSeqElem(sign, i));
cvRectangle (
src,
cvPoint(r.x(), r.y()),
cvPoint(r.width() + r.x(), r.height() + r.y()),
CvScalar.RED,
2,
CV_AA,
0);
}
//Display result
cvShowImage("Result", src);
cvWaitKey(0);
}
/**
* Create the application.
*/
public Form1() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
JLabel Label1 = new JLabel(" ");
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 301, 222);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton btnDetect = new JButton("Detect");
btnDetect.setVerticalAlignment(SwingConstants.TOP);
btnDetect.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//IplImage img = cvLoadImage("resources/lena.jpg");
IplImage img = cvLoadImage(myFileName);
CvMat myImg = Highgui.imread(myFileName);
detect(img);
}
});
frame.getContentPane().add(btnDetect, BorderLayout.SOUTH);
Label1.setHorizontalAlignment(SwingConstants.CENTER);
frame.getContentPane().add(Label1, BorderLayout.CENTER);
JButton btnNewButton = new JButton("Open");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
JFileChooser fileopen = new JFileChooser();
int ret = fileopen.showDialog(null, "Открыть файл");
if (ret == JFileChooser.APPROVE_OPTION) {
File file = fileopen.getSelectedFile();
myFileName = file.getAbsolutePath();
Label1.setText(myFileName);
}
}
});
frame.getContentPane().add(btnNewButton, BorderLayout.NORTH);
}
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Form1 window = new Form1();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
//Load image
//IplImage img = cvLoadImage("resources/lena.jpg");
//detect(img);
}
}
External JARs: http://pasteboard.co/jwqNHC9.png
Full project in ZIP
I've also followed all steps from here: http://opencvlover.blogspot.in/2012/04/javacv-setup-with-eclipse-on-windows-7.html
Any help will be appreciated.
Mat m = Highgui.imread(myFileName); is from the builtin opencv java wrappers , not from javacv ( which is a independant, 3rd party wrapper ).
unfortunately, both concurrent apis are pretty incompatible, as javacv is wrapping the outdated c-api, and the opencv ones are wrapping the more modern c++ api.

Categories

Resources