java Swing Application Freezes when call to jpcapCaptor.openDevice method - java

I am developing some bandwidth utilization monitor tool using jpcap.
what am i doing:-
1. i created a radio buttons panel containing the list of all the network interfaces that is present on system, and user has to choose one of them.
2. a jfreechart panel (dynamic) that will show the real time graph of bandwidth utilization when user clicks GO! button.
problem:-
i have added following in ActionListener in GO! button
try{captor = JpcapCaptor.openDevice(devices[selecteddevice], 65535,true, 20);}catch(Exception e){}
timer.start();
captor.loopPacket(-1,new PacketPrinter());
so when i run the program GUI comes with radiobutton panel and jfreechart panel but when i select an option and press GO! application freezes and chart panel does not show any dynamic updation.
when i commented out the JpcapCaptor.openDevice(devices[selecteddevice], 65535,true, 20);
then when i press GO! button, everything works,for example timer starts and chart panel is being updated.(but as captor is null so it is not capturing any data)
Please Help me!!!
my system is ubuntu 10.04, jpcap 0.7
my code is as follows:-
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.DynamicTimeSeriesCollection;
import org.jfree.data.time.Second;
import org.jfree.data.xy.XYDataset;
import java.util.List;
import java.util.ArrayList;
import jpcap.*;
import jpcap.packet.*;
import java.util.*;
import java.awt.event.*;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.*;
public class Sniffer extends JPanel
{
private static jpcap.NetworkInterface[] devices;
private static int selecteddevice=-1;
JFrame frame;
public static JpcapCaptor captor;
private static final String TITLE="Bandwidth Utilization Meter";;
public static List<Packet> packets;
public static Timer timer;
public static ArrayList<JRadioButton> radioButtonArray = new ArrayList<JRadioButton>();
private ButtonGroup group= new ButtonGroup();
public static JButton go;
JFreeChart chart;
static DynamicTimeSeriesCollection dataset;
public Sniffer()
{
packets = new ArrayList<Packet>();
dataset =new DynamicTimeSeriesCollection(1,120, new Second());
dataset.setTimeBase(new Second(0, 0, 0, 2, 1, 2011));
dataset.addSeries(new float[0], 0, "PPP0 Bandwidth Utilization Meter");
chart = createChart(dataset);
getDevices();
timer = new Timer(1000,new ActionListener(){
public void actionPerformed(ActionEvent e)
{ long tlen=0;
List<Packet> temp = new ArrayList<Packet>(packets);
packets.clear();
for(Packet i : temp)
{
tlen+=i.len;
}
float[] newData = new float[1];
newData[0]=(float)tlen/1024;
dataset.advanceTime();
dataset.appendData(newData);
}});
setGUI();
}
void setGUI()
{
setLayout(new BorderLayout());
frame = new JFrame();
JPanel panel = new JPanel(new GridLayout(devices.length, 1));
for (JRadioButton combo : radioButtonArray)
{
panel.add(combo);
}
JScrollPane scrollPane = new JScrollPane(panel);
go= new JButton("GO!");
go.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ee)
{
//problem starts here.............
try{captor = JpcapCaptor.openDevice(devices[selecteddevice], 65535,true, 20);}catch(Exception e){}
timer.start();
captor.loopPacket(-1,new PacketPrinter());
//.....................................
}
}
);
go.setEnabled(false);
panel.add(go);
add(scrollPane, BorderLayout.CENTER);
scrollPane.setSize(300,300);
JFrame.setDefaultLookAndFeelDecorated(true);
frame.setLayout(new GridLayout(2, 0));
frame.add(scrollPane);
frame.add(new ChartPanel(chart));
frame.setSize(1024, 768);
frame.setTitle("BW");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void getDevices()
{
devices = JpcapCaptor.getDeviceList();
for(int i=0;i<devices.length;i++)
{
String device=null;
radioButtonArray.add(new JRadioButton());
group.add(radioButtonArray.get(i));
radioButtonArray.get(i).addActionListener(new RadioButtonListener());
device= devices[i].name+" "+"("+devices[i].description+")";
radioButtonArray.get(i).setText(device);
}
}
public static void startSniffing() throws Exception
{
captor = JpcapCaptor.openDevice(devices[selecteddevice], 65535,true, 20);
}
public static void setSelectedDevice(int device)
{
selecteddevice = device;
}
public NetworkInterface getSelectedDevice()
{
if (selecteddevice == -1)
{
return null;
}
else
{
return devices[selecteddevice];
}
}
public static void main(String args[])
{
Sniffer sniffer = new Sniffer();
//sniffer.start();
}
private JFreeChart createChart(final XYDataset dataset) {
final JFreeChart xyz = ChartFactory.createTimeSeriesChart(
TITLE, "Time(Seconds)", "Bandwidth KB/s", dataset, true, true, false);
final XYPlot plot = xyz.getXYPlot();
ValueAxis domain = plot.getDomainAxis();
domain.setAutoRange(true);
ValueAxis range = plot.getRangeAxis();
range.setRange(0,1000);
return xyz;
}
}
class RadioButtonListener extends JPanel implements ActionListener {
public void actionPerformed(ActionEvent e) {
Sniffer.go.setEnabled(true);
for (JRadioButton radio : Sniffer.radioButtonArray) {
if (radio.isSelected()) {
Sniffer.setSelectedDevice(Sniffer.radioButtonArray.indexOf(radio));
}
}
}
}
class PacketPrinter implements PacketReceiver {
static long tlen;
public void receivePacket(Packet packet) {
Sniffer.packets.add(packet);
}
}

Don't block the EDT. Put the time consuming task in a SwingWorker.

Related

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 to hide Swing accelerators by a text pane?

I have a Swing application with multiple panes. Some of the panes are text ones (JTextPane), some are dialog-like (with buttons and sliders) and some are graphical (custom painted ). I have a few actions defined in the main menu with simple accelerators like K, P or O.
I would like those accelerators to be processed by the menu actions only if the currently focused pane is not processing them. Specifically, I do not want them to be processed by the menu when the user is just typing in a text pane.
I am creating actions and menu items using:
action = new javax.swing.AbstractAction
new MenuItem(action)
I am registering accelerators with:
action.putValue(javax.swing.Action.ACCELERATOR_KEY, keyStroke)
Is it possible to "eat" (suppress) the key press event for the keys which are processed in the text panes so that they are not passed to the main menu for the global processing?
If not, are there some alternatives to do something similar, like to register the accelerators I know should not be processed when in a text pane for some panes only?
I am adding a code based on an answer to make the question clearer (and to make developing alternate solutions easier):
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
public class TestMenuBindings {
public static void main(String[] args) {
JMenuBar menuBar = new JMenuBar();
final JMenu menu = new JMenu("Print");
final Action oAction = new PrintAction("O",KeyStroke.getKeyStroke(KeyEvent.VK_O, 0));
menu.add(oAction);
menuBar.add(menu);
JFrame frm = new JFrame("Frame");
frm.setJMenuBar(menuBar);
JTextArea area = new JTextArea("Here I want no accelerators", 10, 40);
frm.add(new JScrollPane(area));
frm.add(new JTextField("Here I want accelerators working"), BorderLayout.SOUTH);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static class PrintAction extends AbstractAction {
private String str;
public PrintAction(String aPrintStr, KeyStroke aMnemonic) {
super("Print: " + aPrintStr);
str = aPrintStr;
putValue(Action.ACCELERATOR_KEY, aMnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(str);
}
}
}
Here is the example. In text area no key bindings working. In text field work all key bindings. Also all the menu items are accessible (enabled) from the menu.
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
public class TestMenuBindings {
public static void main(String[] args) {
JMenuBar menuBar = new JMenuBar();
final JMenu menu = new JMenu("Print");
menu.add(new PrintAction("O", KeyStroke.getKeyStroke(KeyEvent.VK_O, 0)));
menu.add(new PrintAction("K", KeyStroke.getKeyStroke(KeyEvent.VK_K, 0)));
menu.add(new PrintAction("P", KeyStroke.getKeyStroke(KeyEvent.VK_P, 0)));
menuBar.add(menu);
JFrame frm = new JFrame("Frame");
frm.setJMenuBar(menuBar);
JTextArea area = new JTextArea("Here working no accelerators", 10, 40);
area.addFocusListener(new FocusListener() {
#Override
public void focusLost(FocusEvent e) {
setItemStatus(menu, true);
}
#Override
public void focusGained(FocusEvent e) {
setItemStatus(menu, false);
}
});
frm.add(new JScrollPane(area));
frm.add(new JTextField("Here working accelerators"), BorderLayout.SOUTH);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static void setItemStatus(JMenu aMenu, boolean aStatus) {
for (Component item : aMenu.getMenuComponents()) {
((JMenuItem) item).getAction().setEnabled(aStatus);
}
}
private static class PrintAction extends AbstractAction {
private String str;
public PrintAction(String aPrintStr, KeyStroke aMnemonic) {
super("Print: " + aPrintStr);
str = aPrintStr;
putValue(Action.ACCELERATOR_KEY, aMnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(str);
}
}
}
Here is a solution using KeyBindinds, as suggested by camickr. It is shorter than the one provided by Sergiy Medvynskyy, and I find it more straightforward, but it has a drawback the shortcut is not displayed in the menu, which is a result of the shortcut not being defined in the action itself.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
public class TestMenuBindings {
public static void main(String[] args) {
JMenuBar menuBar = new JMenuBar();
final JMenu menu = new JMenu("Print");
final Action oAction = new PrintAction("O");
menu.add(oAction);
menuBar.add(menu);
JFrame frm = new JFrame("Frame");
frm.setJMenuBar(menuBar);
JTextArea area = new JTextArea("Here working no accelerators", 10, 40);
frm.add(new JScrollPane(area));
frm.add(new JTextField("Here working accelerators") {
{
getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_O, 0), "command_O");
getActionMap().put("command_O", oAction);
}
}, BorderLayout.SOUTH);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static class PrintAction extends AbstractAction {
private String str;
public PrintAction(String aPrintStr) {
super("Print: " + aPrintStr);
str = aPrintStr;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(str);
}
}
}
It is possible to use KeyEventDispatcher to filter key events.
(Credit: I have adapted the code from answer to Application wide keyboard shortcut)
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class TestMenuBindings {
public static void main(String[] args) {
JMenuBar menuBar = new JMenuBar();
final JMenu menu = new JMenu("Print");
final Action oAction = new PrintAction("O",KeyStroke.getKeyStroke(KeyEvent.VK_O, 0));
menu.add(oAction);
menuBar.add(menu);
JFrame frm = new JFrame("Frame");
frm.setJMenuBar(menuBar);
final JTextArea area = new JTextArea("Here working no accelerators", 10, 40);
frm.add(new JScrollPane(area));
frm.add(new JTextField("Here working accelerators"), BorderLayout.SOUTH);
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
kfm.addKeyEventDispatcher( new KeyEventDispatcher() {
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e);
// pass only KEY_TYPED for letters with no modifiers in the editing area, suppress KEY_PRESSED, KEY_RELEASED
return area.isFocusOwner() && keyStroke.getModifiers()==0 && e.getID()!=KeyEvent.KEY_TYPED && Character.isLetter(e.getKeyChar());
}
});
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static class PrintAction extends AbstractAction {
private String str;
public PrintAction(String aPrintStr, KeyStroke aMnemonic) {
super("Print: " + aPrintStr);
str = aPrintStr;
putValue(Action.ACCELERATOR_KEY, aMnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(str);
}
}
}

AWT button not clickable in VLCJ

I have created a simple VLCJ project that consists of a simple embedded player and a button to exit.
The code is as follows:
package test;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import uk.co.caprica.vlcj.binding.LibVlc;
import uk.co.caprica.vlcj.component.EmbeddedMediaPlayerComponent;
import uk.co.caprica.vlcj.runtime.RuntimeUtil;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
public class Demo {
private final JFrame frame;
private final EmbeddedMediaPlayerComponent mediaPlayerComponent;
private JPanel videoPane;
private JPanel buttonPane;
private Button exitButton;
private ActionListener a;
private static String vlc_location = "C:\\Program Files\\VideoLAN\\VLC";
public static void main(String[] args) {
NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), vlc_location);
Native.loadLibrary(RuntimeUtil.getLibVlcLibraryName(), LibVlc.class);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Demo().run();
}
});
}
public Demo() {
mediaPlayerComponent = new EmbeddedMediaPlayerComponent();
a = new MyActionListener();
exitButton = new Button("Exit");
exitButton.setActionCommand("Exit app");
exitButton.addActionListener(a);
buttonPane = new JPanel();
buttonPane.setLayout(new BorderLayout());
buttonPane.setBackground(Color.black);
buttonPane.add(exitButton, BorderLayout.CENTER);
videoPane = new JPanel();
videoPane.setLayout(new BorderLayout());
videoPane.setBackground(Color.black);
videoPane.add(mediaPlayerComponent, BorderLayout.CENTER);
videoPane.add(buttonPane, BorderLayout.PAGE_END);
frame = new JFrame("vlcj demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(100, 100);
frame.setSize(1200, 800);
frame.setContentPane(videoPane);
frame.setVisible(true);
}
public void run() {
mediaPlayerComponent.getMediaPlayer().playMedia(video_file);
}
class MyActionListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent arg0) {
String s = arg0.getActionCommand();
if (s.equals("Exit")) {
System.exit(0);
}
}
}
}
The problem is that the button does show up but it cannot be clicked. When i removed the videoPane, it was back to clickable! Any ideas if I'm missing something?
I am using the version 2.1.0 for vlcj.
Thanks!
Thanks MadProgrammer for your advise. I went on to think about it and tried commenting away the line of code in run(). The JButton came back!
However, when i un-commented the code in run(), the JButton disappeared. I was thinking maybe the Swing runnable was causing issue with the creation of the JButton.
Hence, what i did was to comment away the whole Swing runnable and just use:
final Demo demo = new Demo();
demo.run();
The demo can now play video and display the Exit button, thanks!

Displaying image on clicking JButton

Im trying to display an image upon clicking a JButton but upon execution the image is not displayed when button is clicked.
import javax.swing.JButton;
import javax.swing.JFrame;
import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JApplet;
import java.awt.*;
public class new2 extends JFrame implements ActionListener
{
private boolean b1,b2;
Container contentPane= getContentPane();
JButton awar=new JButton("#war");
JButton arrow=new JButton("arrow");
private Image image1,image2;
public new2()
{
setSize(400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane.setLayout(new FlowLayout());
awar.addActionListener(this);
contentPane.add(awar).setVisible(true);
arrow.addActionListener(this);
contentPane.add(arrow).setVisible(true);
}
public void init()
{
image1=Toolkit.getDefaultToolkit().getImage("#war.jpeg");
image2=Toolkit.getDefaultToolkit().getImage("arrow.gif");
}
public void paint(Graphics g)
{
if(b1==true)
{
g.drawImage(image1,0,0,this);
}
else if(b2==true)
{
g.drawImage(image2,0,0,this);
}
}
public void actionPerformed(ActionEvent event)
{
String actionCommand = event.getActionCommand();
if(actionCommand.equals("#war"))
{
b1=true;
}
else if(actionCommand.equals("arrow"))
{
b2=true;
}
}
public static void main(String args[])
{
new2 m=new new2();
m.setVisible(true);
}
}
..display an image upon clicking a JButton but upon execution the image is not displayed when button is clicked.
Use a JToggleButton as shown here.
The buttons should set the boolean variables, but your paint2 is never called after the action preformed method. Secondly, it doesn't really even paint anything, it never gets graphics and will cause NPEs.
You should override the JFrame.paint(Graphics g) method.
Whenever you want to refresh the content of the JFrame instance call the JFrame.repaint() method.
/**
*
*/
package com.samples;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
/**
* #author
*
*/
public class MyFrame extends JFrame implements ActionListener {
private static String SHOW_ACTION = "show";
private static String HIDE_ACTION = "hide";
private Image image = null;
private boolean showImage = false;
public MyFrame(String filename) {
setTitle("MyWindow");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(800, 600);
this.image = new ImageIcon(filename).getImage();
Container container = getContentPane();
container.setLayout(new BorderLayout());
container.add(createControls(), BorderLayout.SOUTH);
}
private JPanel createControls() {
JButton showButton = new JButton("Show");
showButton.addActionListener(this);
showButton.setActionCommand(SHOW_ACTION);
JButton hideButton = new JButton("Hide");
hideButton.addActionListener(this);
hideButton.setActionCommand(HIDE_ACTION);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout(FlowLayout.CENTER));
panel.add(showButton);
panel.add(hideButton);
return panel;
}
#Override
public void paint(Graphics g) {
super.paint(g);
if (showImage) {
g.drawImage(image, 0, 0, image.getWidth(null), image.getHeight(null), null);
}
}
#Override
public void actionPerformed(ActionEvent event) {
String actionCommand = event.getActionCommand();
if (SHOW_ACTION.equals(actionCommand)) {
showImage = true;
} else if (HIDE_ACTION.equals(actionCommand)) {
showImage = false;
}
repaint();
}
/**
* #param args
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
MyFrame frame = new MyFrame("resources/image.jpg");
frame.setVisible(true);
}
});
}
}

Java tabbed panes within internal frame

I am trying to get an internal frame to contain tabbed panes. However, my code does not seem to be loading the panes into the internal frame. I have my code in the java files, called InternalFrame.java and TabbedPaneSample.java. The code for both files is included below. Can anyone show me how to fix the code below so that it loads the tabbed panes when I run InternalFrame.java?
Here is my code:
The code for InternalFrame.java is:
package test;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane;
public class InternalFrame extends JFrame {
JButton openButton;
JLayeredPane desktop;
JInternalFrame internalFrame;
TabbedPaneSample myTabbedPaneSample = new TabbedPaneSample();
public InternalFrame() {
super("Click button to open internal frame with two panels.");
setSize(500, 400);
openButton = new JButton("Open");
Panel p = new Panel();
p.add(openButton);
add(p, BorderLayout.SOUTH);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
openButton.addActionListener(new OpenListener());
desktop = new JDesktopPane();
desktop.setOpaque(true);
add(desktop, BorderLayout.CENTER);
}
class OpenListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if ((internalFrame == null) || (internalFrame.isClosed())) {
internalFrame = new JInternalFrame("Internal Frame", true, true, true, true);
internalFrame.setBounds(50, 50, 200, 100);
internalFrame.add(myTabbedPaneSample, BorderLayout.CENTER);
internalFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
internalFrame.pack();
internalFrame.setMinimumSize(new Dimension(300, 300));
desktop.add(internalFrame, new Integer(1));
internalFrame.setVisible(true);
}
}
}
public static void main(String args[]) {
InternalFrame myInternalFrame = new InternalFrame();
myInternalFrame.setVisible(true);
}
}
And the code for TabbedPaneSample.java is:
package test;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
public class TabbedPaneSample extends JTabbedPane {
private JTabbedPane tabbedPane = new JTabbedPane();
private ImageIcon closeImage = new ImageIcon("C:/test/shipIcon.gif");
private Dimension closeButtonSize;
private int tabCounter = 0;
public TabbedPaneSample() {
closeButtonSize = new Dimension(closeImage.getIconWidth() + 2, closeImage.getIconHeight() + 2);
}
public void add() {
final JPanel content = new JPanel();
JPanel tab = new JPanel();
tab.setOpaque(false);
JLabel tabLabel = new JLabel("Tab " + (++tabCounter));
JButton tabCloseButton = new JButton(closeImage);
tabCloseButton.setPreferredSize(closeButtonSize);
tabCloseButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int closeTabNumber = tabbedPane.indexOfComponent(content);
tabbedPane.removeTabAt(closeTabNumber);
}
});
tab.add(tabLabel, BorderLayout.WEST);
tab.add(tabCloseButton, BorderLayout.EAST);
this.addTab(null, content);
this.setTabComponentAt(this.getTabCount() - 1, tab);
}
public static void main(String[] args) {
TabbedPaneSample main = new TabbedPaneSample();
main.add();
main.add();
}
}
Here's one approach, shown below. A more flexible approach using Action is referenced here.
Addendum: Reviewing your code, you should let the various layout managers and component preferred sizes do more of the work, as shown. In particular, this.setPreferredSize() is done for demonstration purposes. In a real application, you would restore user size and location preferences.
package overflow;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
/** #see https://stackoverflow.com/posts/6514889 */
public class InternalFrame extends JFrame {
JButton openButton;
JLayeredPane desktop;
JInternalFrame internalFrame;
public InternalFrame() {
super("Click button to open internal frame with two tabs.");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setPreferredSize(new Dimension(400, 400));
openButton = new JButton("Open");
JPanel p = new JPanel();
p.add(openButton);
this.add(p, BorderLayout.SOUTH);
openButton.addActionListener(new OpenListener());
desktop = new JDesktopPane();
this.add(desktop, BorderLayout.CENTER);
this.pack();
this.setLocationRelativeTo(null);
}
class OpenListener implements ActionListener {
private static final int DELTA = 40;
private int offset = DELTA;
public void actionPerformed(ActionEvent e) {
internalFrame = new JInternalFrame(
"Internal Frame", true, true, true, true);
internalFrame.setLocation(offset, offset);
offset += DELTA;
internalFrame.add(createTabbedPane());
desktop.add(internalFrame);
internalFrame.pack();
internalFrame.setVisible(true);
}
}
private JTabbedPane createTabbedPane() {
JTabbedPane jtp = new JTabbedPane();
createTab(jtp, "One");
createTab(jtp, "Two");
return jtp;
}
private void createTab(JTabbedPane jtp, String s) {
jtp.add(s, new JLabel("TabbedPane " + s, JLabel.CENTER));
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
InternalFrame myInternalFrame = new InternalFrame();
myInternalFrame.setVisible(true);
}
});
}
}
First of all, I think Finally, I think you shouldn't use desktop.add(internalFrame, new Integer(1)) but rather desktop.add(internalFrame) instead, the reason is that JDesktopPane uses its layers (it is a JLayeredPane subclass) internally, and I don't think you should play with layers yourself.
Then, following this problem I had once with JInternalFrame, I would advise you call pack() after adding the internal frame to the desktop pane.
Hence, you should try with your OpenListener class looking like this:
class OpenListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if ((internalFrame == null) || (internalFrame.isClosed())) {
internalFrame = new JInternalFrame("Internal Frame", true, true, true, true);
internalFrame.setBounds(50, 50, 200, 100);
internalFrame.add(myTabbedPaneSample, BorderLayout.CENTER);
internalFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// internalFrame.pack();
internalFrame.setMinimumSize(new Dimension(300, 300));
// desktop.add(internalFrame, new Integer(1));
desktop.add(internalFrame);
internalFrame.pack();
internalFrame.setVisible(true);
}
}
}
Besides, I also agree with trashgod comments on Action of course and the simplifying rework he has done on your snippet.
I preferred to create in my Main Frame class (which extends JFrame) the following function:
private void showIntFrame(Class intFrameClass) {
JInternalFrame targetFrame = null;
int xoff = 0, yoff = 0;
for(JInternalFrame jif : jdp.getAllFrames()) {
if(jif.getClass().equals(intFrameClass))
targetFrame = jif;
if(jif.getLocation().x > xoff)
xoff = jif.getLocation().x;
if(jif.getLocation().y > yoff)
yoff = jif.getLocation().y;
}
if(targetFrame == null) {
try {
Constructor<JInternalFrame> c = intFrameClass.getConstructor(MainFrame.class);
targetFrame = c.newInstance(MainFrame.this);
} catch (Exception ex) {
System.err.println("Exception in MainFrame.showIntFrame() while creating new JInternalFrame instance. " + ex.getLocalizedMessage());
ex.printStackTrace();
return;
}
jdp.add(targetFrame);
targetFrame.setLocation(xoff + 30, yoff + 30);
}
targetFrame.setVisible(true);
try {
targetFrame.setSelected(true);
} catch (PropertyVetoException ex) {
System.err.println("PropertyVetoException in MainFrame.showIntFrame() while activating JInternalFrame instance. " + ex.getLocalizedMessage());
}
}
Here jdp is instance of JDesktopPane, which previously was set as ContentPane of my main JFrame.
Because my programs often contain numbers of different classes, inherited from JInternalFrame, it is easier to call this function from event handlers to show new subclass of JInternalFrame.
Every subclass of JInternalFrame in my programs have one constructor with one parameter - MainFrame (main JFrame).

Categories

Resources