How to implement JScrollPane child behavior? - java

It is said in manual, that if child does not implement Scrollable, then JScrollPane rely on preferredSize properties of it's content.
Apparently this is not true for me. I am increasing preferred height, but JScrollPane does not feel or react on it.
package tests;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Timer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Try01_JScrollPane extends JFrame {
private static final long serialVersionUID = 4123186105171813186L;
private static final Logger log = LoggerFactory.getLogger(Try01_JScrollPane.class);
JPanel yellowPanel = new JPanel();
{
yellowPanel.setPreferredSize(new Dimension(200,50));
yellowPanel.setSize(new Dimension(200,50));
yellowPanel.setBackground(Color.yellow);
}
JScrollPane scrollPane = new JScrollPane(yellowPanel);
{
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
}
AbstractAction increaseAction = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
yellowPanel.setPreferredSize(new Dimension(yellowPanel.getPreferredSize().width, yellowPanel.getPreferredSize().height+100));
log.debug("preferred height is now {}", yellowPanel.getPreferredSize().height);
}
};
Timer increaseTimer = new Timer(1000, increaseAction);
{
setLayout(new BorderLayout());
add(scrollPane, BorderLayout.CENTER);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(200, 400);
setTitle("Try01_JScrollPane");
increaseTimer.start();
setVisible(true);
}
public static void main(String[] args) {
new Try01_JScrollPane();
}
}

JPanel is container and JComponent too, for any changes to JViewport you have to notify the JScrollPane:-)
.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Try01_JScrollPane extends JFrame {
private static final long serialVersionUID = 4123186105171813186L;
private JFrame frame = new JFrame("Try01_JScrollPane");
private JPanel yellowPanel = new JPanel();
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
{
yellowPanel.setBackground(Color.yellow);
}
private JScrollPane scrollPane = new JScrollPane(yellowPanel);
{
scrollPane.setPreferredSize(new Dimension(400, 300));
}
private AbstractAction increaseAction = new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
yellowPanel.setPreferredSize(
new Dimension(yellowPanel.getPreferredSize().width + 100,
yellowPanel.getPreferredSize().height + 100));
yellowPanel.revalidate();
yellowPanel.repaint();
}
};
private Timer increaseTimer = new Timer(1000, increaseAction);
public Try01_JScrollPane() {
frame.add(scrollPane, BorderLayout.CENTER);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
increaseTimer.start();
increaseTimer.setRepeats(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Try01_JScrollPane();
}
});
}
}

The JScrollPane cuts a view port out of a backing content have a scroll pane layout. The part on getPreferredSize refers to this layout. It simply says that the JScrollPane / view port rectangle is not influenced by the backing content and vice versa: content is layed out with respect to their preferred size.
So a change of preferred size need a new layouting. More sence would be to:
initialize with a setPreferredSize.
afterwards call setSize to resize.

Related

How do I update a JLabel during run time

the JLabel's name is set to an int which changes as the user modifies the number, i tried label.revalidate and Label.repaint after the user changes the int value. i have seen in similar questions people suggest creating a new jlabel everytime, but im wondering if there is a simpler way? the code is very long so i will summerize when needed.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class officia {
static JFrame Frame;
static JPanel Panel;
static JTextField healthPlace;
static String health="0";
static JButton begin;
static JLabel heart;
static int loop;
public static void main(String[] args) {
Panel = new JPanel();
Frame = new JFrame();
Frame.setSize(500,1000);
Frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Frame.add(Panel);
Panel.setLayout(null);
//adds panel and frame
healthPlace = new JTextField();
healthPlace.setBounds(170, 130, 165, 25);
Panel.add(healthPlace);
begin = new JButton("Begin");
begin.setBounds(217, 185, 70, 25);
Panel.add(begin);
while(loop==1)
loop=0;
heart = new JLabel(health);
heart.setBounds(150, -85, 500, 500);
Panel.add(heart);
Frame.setVisible(true);
//inputs gui's
ActionListener beginPressed = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
health = healthPlace.getText();
loop=1;
}
};
begin.addActionListener(beginPressed);
}
}
You're working in a event driven environment, that is, something happens and you respond to it.
This means, you're while-loop is ill-conceived and is probably the source of your issue. How can the ActionListener for the button be added when the loop is running, but you seem to using the ActionListener to exit the loop...
I modified you code slightly, so when you press the button, it will update the label.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class officia {
static JFrame Frame;
static JPanel Panel;
static JTextField healthPlace;
static String health = "0";
static JButton begin;
static JLabel heart;
static int loop;
public static void main(String[] args) {
Panel = new JPanel();
Frame = new JFrame();
Frame.setSize(500, 1000);
Frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Frame.add(Panel);
Panel.setLayout(null);
//adds panel and frame
healthPlace = new JTextField();
healthPlace.setBounds(170, 130, 165, 25);
Panel.add(healthPlace);
begin = new JButton("Begin");
begin.setBounds(217, 185, 70, 25);
Panel.add(begin);
// This is ... interesting, but a bad idea
// while (loop == 1) {
// loop = 0;
// }
heart = new JLabel(health);
heart.setBounds(150, -85, 500, 500);
Panel.add(heart);
Frame.setVisible(true);
//inputs gui's
ActionListener beginPressed = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
health = healthPlace.getText();
loop ++;
heart.setText(Integer.toString(loop));
}
};
begin.addActionListener(beginPressed);
}
}
JLabel#setText is what's known as a stateful property, that is, it will trigger an update that will cause it to be painted, so, if it's not updating, you're doing something wrong.
Possible runnable example (of what I think you want to do)
You're working a very rich UI framework. One if it's, many, features, is the layout management framework, something you should seriously take the time to learn to understand and use.
See Laying Out Components Within a Container for more details.
Below is a relatively simple example which shows one way you might "swicth" between views based on a response to a user input
import java.awt.CardLayout;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new BasePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class BasePane extends JPanel {
private CardLayout cardLayout;
public BasePane() {
cardLayout = new CardLayout();
setLayout(cardLayout);
StartPane startPane = new StartPane(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(BasePane.this, "HeartPane");
}
});
HeartPane heartPane = new HeartPane();
add(startPane, "StartPane");
add(heartPane, "HeartPane");
}
}
public class StartPane extends JPanel {
public StartPane(ActionListener actionListener) {
setBorder(new EmptyBorder(10, 10, 10, 10));
setLayout(new GridBagLayout());
JButton start = new JButton("Begin");
add(start);
start.addActionListener(actionListener);
}
}
public class HeartPane extends JPanel {
private JTextField heartTextField;
private JLabel heartLabel;
public HeartPane() {
setBorder(new EmptyBorder(10, 10, 10, 10));
setLayout(new GridBagLayout());
heartLabel = new JLabel("Heart");
heartTextField = new JTextField(10);
add(heartLabel);
add(heartTextField);
}
}
}

JDialog only load at the end of the program

I am using a JDialog for a project, which is load when I click on a button located inside a JFrame.
This JDialog is supposed to display an image, but the image appears only when the code called by the JFrame class is executed. My problem is that I want the image to be displayed when I call it, not at the end of my programm.
Here is my code of the JDialog :
public class LoadingWindow {
private JDialog dialog;
public LoadingWindow() {
this.dialog = new JDialog();
this.dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
this.dialog.setTitle("Veuillez patienter");
this.dialog.setSize(300, 200);
URL url = LoadingWindow.class.getResource("/images/wait.gif");
ImageIcon icon = new ImageIcon(url);
JLabel imageLabel = new JLabel();
imageLabel.setIcon(icon);
imageLabel.setHorizontalAlignment(JLabel.CENTER);
imageLabel.setVerticalAlignment(JLabel.CENTER);
this.dialog.getContentPane().add(imageLabel);
this.dialog.setLocationRelativeTo(null);
this.dialog.setVisible(true);
}
public void stop() {
this.dialog.dispose();
}
}
Inside my JFrame, I call the JDialog this way :
MyJDialog mjd = new MyJDialog ();
[CODE]
mjd.stop();
Thanks !
Here's an example of a GUI that opens a JDialog.
Here's the image I used.
I create a JFrame and a JPanel with a JButton. The JButton has an ActionListener that opens a JDialog. The JDialog displays the car image.
Here's the complete runnable code I used.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class JDialogTest implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new JDialogTest());
}
private JFrame frame;
#Override
public void run() {
frame = new JFrame("JDialog Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(
150, 100, 150, 100));
panel.setPreferredSize(new Dimension(400, 400));
JButton button = new JButton("Open JDialog");
button.addActionListener(new ButtonListener());
panel.add(button);
return panel;
}
public class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
new CalculateDecor(frame, "Spash Screen");
}
}
public class CalculateDecor extends JDialog {
private static final long serialVersionUID = 1L;
public CalculateDecor(JFrame frame, String title) {
super(frame, true);
Image image = getImage();
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setTitle(title);
JPanel panel = new JPanel(new BorderLayout());
JLabel label = new JLabel();
label.setHorizontalAlignment(JLabel.CENTER);
label.setIcon(new ImageIcon(image));
panel.add(label);
add(panel);
pack();
setLocationRelativeTo(frame);
setVisible(true);
System.out.println(getDecorationSize());
}
private Dimension getDecorationSize() {
Rectangle window = getBounds();
Rectangle content = getContentPane().getBounds();
int width = window.width - content.width;
int height = window.height - content.height;
return new Dimension(width, height);
}
private Image getImage() {
try {
return ImageIO.read(getClass().getResourceAsStream(
"/car.jpg"));
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
}

When does a Java Swing JScrollBar update its size?

I have a JTextArea in a JScrollPane, to which I append messages with display.append(). I am trying to make it scroll automatically by setting the value of the scroll bar to the maximum after appending the text. However, the value of getVerticalScrollBar().getMaximum()doesn't get updated immediately after a line is appended. I have tried to force an update with revalidate(), repaint() and updateUI(), but seem unable to find the right function.
MWE:
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class MessageDisplayPane extends JScrollPane {
private static final long serialVersionUID = 2025745714938834689L;
public static final int NUM_LINES = 5;
private JTextArea display;
private JScrollBar vertical = getVerticalScrollBar();
public MessageDisplayPane() {
display = createTextArea();
setViewportView(display);
}
private JTextArea createTextArea() {
JTextArea ta = new JTextArea(NUM_LINES, 0);
ta.setEditable(false);
ta.setLineWrap(true);
ta.setWrapStyleWord(true);
ta.setFont(new Font("Arial", Font.PLAIN, 12));
ta.setBorder(BorderFactory.createEtchedBorder());
return ta;
}
class EventListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
new Thread() {
#Override
public void run() {
System.out.println(vertical.getMaximum());
display.append("test\r\n");
revalidate();
repaint();
updateUI();
System.out.println(vertical.getMaximum());
System.out.println();
//vertical.setValue(vertical.getMaximum());
}
}.start();
}
}
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
MessageDisplayPane messagePane = new MessageDisplayPane();
JButton button = new JButton("Display another line");
frame.setSize(800, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.getContentPane().add(button, BorderLayout.CENTER);
frame.getContentPane().add(messagePane, BorderLayout.SOUTH);
button.addActionListener(messagePane.new EventListener());
frame.setVisible(true);
}
});
}
}
A possible solution could be to set the caret position to the end (or the beginning) of your text, something like :
textArea.setCaretPosition (textArea.getText ().length ()); // to scroll to the bottom
textArea.setCaretPosition (0); // to scroll to the top
I used a similar instruction to set caret position to 0, and the scrollbar did automatically scroll to the top, so it should work for you.

How to make two JPanels listen to the same event?

I have a JFrame and, inside this JFrame there are two JPanels. When I press a key, both of them must listen to this key event and act. I want to take all the keyboard events, and deliver them to both of the JPanels. Do you know how to do it?
Edit: Since they must do different things, I need two different listeners, sorry for not being specific.
Edit2: I made a simple code to show you the problem. When I press the up key, both of the JPanels displayed must change their string; in this code only one of them actually react!
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
/**
*
* #author antonioruffolo
*/
public class TwoPanelsTest extends JFrame {
public TwoPanelsTest() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
setSize(800, 600);
PanelTest panelTest1= new PanelTest();
PanelTest panelTest2= new PanelTest();
GridBagLayout layout= new GridBagLayout();
this.setLayout(layout);
GridBagConstraints c = new GridBagConstraints();
c.ipadx = 220;
c.ipady = 390;
c.insets.right= 0;
c.insets.left=30;
layout.setConstraints(panelTest1, c);
this.add(panelTest1);
layout.setConstraints(panelTest2, c);
c.ipadx = 220;
c.ipady = 390;
c.insets.right=250;
c.insets.left=50;
this.add(panelTest2);
setVisible(true);
setLocationRelativeTo(null);
setTitle("Test");
setFocusable(false);
}
private class PanelTest extends JPanel{
private String string="I'm not called by the event";
private InputMap inputmap;
private ActionMap actionmap;
public PanelTest(){
setFocusable(false);
setDoubleBuffered(true);
this.setBackground(Color.WHITE);
inputmap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputmap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");
actionmap = getActionMap();
actionmap.put("up", new ActionController(this));
}
public void setString(String string){
this.string=string;
}
#Override
public void paintComponent( Graphics g){
super.paintComponent(g);
Font infoFont= new Font("OCR A Std", Font.BOLD, 10);
g.setFont(infoFont);
g.drawString(string, 10, 50);
}
}//PanelTest
private class ActionController extends AbstractAction{
private PanelTest panel;
public ActionController (PanelTest panel){
this.panel=panel;
}
#Override
public void actionPerformed(ActionEvent ae) {
panel.setString("Action performed");
panel.repaint();
}
}
public static void main(String[] args) {
TwoPanelsTest t = new TwoPanelsTest();
}
}
Instead of KeyListener, use Key Bindings and have distinct Action implementations for each panel. By using the WHEN_ANCESTOR_OF_FOCUSED_COMPONENT input map, both panels can respond.
Addendum: Because the search ends after finding a valid binding for the key, the example below forwards the event to the elements of a List<MyPanel>, each of which can respond differently via an available Action.
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.Arrays;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
/** #see http://stackoverflow.com/q/10011564/230513 */
public class TwoPanelsTest extends JFrame {
private MyPanel one = new MyPanel("One");
private MyPanel two = new MyPanel("Two");
private List<MyPanel> list = Arrays.asList(one, two);
public TwoPanelsTest() {
super("TwoPanelsTest");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridLayout(0, 1, 10, 10));
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
panel.add(one);
panel.add(two);
panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");
panel.getActionMap().put("up", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
for (MyPanel panel : list) {
panel.getAction().actionPerformed(e);
}
}
});
this.add(panel);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
private static class MyPanel extends JPanel {
private String string = " will be updated though its action.";
private Action action = new UpdateAction(this);
private String name;
private JLabel label;
public MyPanel(String name) {
this.name = name;
this.label = new JLabel(name + string, JLabel.CENTER);
this.setLayout(new GridLayout());
this.setFocusable(true);
this.add(label);
}
public Action getAction() {
return action;
}
private void update() {
label.setText(name + ": " + System.nanoTime());
}
private static class UpdateAction extends AbstractAction {
private MyPanel panel;
public UpdateAction(MyPanel panel) {
this.panel = panel;
}
#Override
public void actionPerformed(ActionEvent ae) {
panel.update();
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
TwoPanelsTest t = new TwoPanelsTest();
}
});
}
}
One of the ways is use methods from SwingUtilities for Java6 (notice SwingUtilities for Java7 have got a few changes, but not important in this case) is possible to redirect, distribute, multiple events that came from Standard Swing Listeners, simple example about redirect mouse events from one container to the another,
You should create a XXListener implementation and add that listener by .addXXListener to all the components you need.
You can use the observer pattern for this.
http://en.wikipedia.org/wiki/Observer_pattern
MyKeyEventListener listener = new MyKeyEventListener();
JPanel one = new JPanel();
one.addKeyListener(listener);//method might be wrong
JPanel two = new JPanel();
two.addKeyListener(listener);
listener.addObserver(one);
listener.addObserver(two);

Double List Item insertion in JTextPane

I have a button that inserts an unordered list item into a JTextPane. However, when I click on the button to insert a list item, two bullets are inserted instead of one. One bullet is inserted only during the first time insertion.
I cut out the functionality from my application and pasted the code into a small SSCCE (below) and the problem remains. Does anyone have any idea as to what might be happening here?
[The problem has been solved, below is the complete solved code. There are two ways to do this, refer to the functionality in the show and the bullets button]
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.ElementIterator;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
public class Main {
private static Button2 show = new Button2 ("Show");
private static LIButton bullets = new LIButton("Bullets", HTML.Tag.UL);
private static JEditorPane pane = new JEditorPane();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
create();
}
});
}
private static void create() throws HeadlessException {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pane.setPreferredSize(new Dimension(300, 300));
pane.setContentType("text/html");
frame.add(pane, BorderLayout.CENTER);
JPanel panel = new JPanel();
panel.add(bullets);
panel.add(show);
frame.add(panel, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
static class LIButton extends JButton {
static final String LI_HTML = "<HTML><BODY><UL><LI></LI></UL></BODY></HTML>";
public LIButton(String name, HTML.Tag parent) {
super(new HTMLEditorKit.InsertHTMLTextAction(
name, LI_HTML, HTML.Tag.UL, HTML.Tag.LI, HTML.Tag.BODY, HTML.Tag.UL));
}
}
static class Button2 extends JButton implements ActionListener {
static final String LI_HTML = "<HTML><BODY><UL><LI></LI></UL></BODY></HTML>";
public Button2(String name) {
super(name);
this.addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent ae) {
HTMLDocument doc = (HTMLDocument) pane.getDocument();
HTMLEditorKit kit = (HTMLEditorKit) pane.getEditorKit();
try {
kit.insertHTML(doc, doc.getLength() - 1, LI_HTML, 0, 1, null);
} catch (BadLocationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
The example below seems to work.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.HeadlessException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLEditorKit;
public class Main {
private static LIButton bullets = new LIButton("Bullets", HTML.Tag.UL);
private static JTextPane pane = new JTextPane();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
create();
}
});
}
private static void create() throws HeadlessException {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pane.setPreferredSize(new Dimension(300, 300));
pane.setContentType("text/html");
pane.setText("<HTML><BODY><UL></UL></BODY></HTML>");
frame.add(pane, BorderLayout.CENTER);
JPanel panel = new JPanel();
panel.add(bullets);
frame.add(panel, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
static class LIButton extends JButton {
static final String LI_HTML = "<LI>item</LI>";
public LIButton(String name, HTML.Tag parent) {
super(new HTMLEditorKit.InsertHTMLTextAction(
name, LI_HTML, parent, HTML.Tag.LI));
}
}
}

Categories

Resources