For some reason my HTML page is not appearing 100% on screen when it should, it looks like a timing issue to me. If I remove scrollpane and use just EditorPane it works ok.
What kind of code should I add below to force java applet screen to redraw/refresh and can I somehow wait until all images were really loaded ok? Currently images are drawn a bit after text is visible on GUI.
(the gray goes away and missing text appears when I minimize+maximize window.)
I use SynchronousHTMLEditorKit as m_editorPane.setEditorKitForContentType
private JEditorPane m_editorPane = new JTextPane();
private JScrollPane m_scrollPane = new JScrollPane();
....
JEditorPane.registerEditorKitForContentType( "text/html", "SynchronousHTMLEditorKit" );
m_editorPane.setEditorKitForContentType( "text/html", new SynchronousHTMLEditorKit() );
m_editorPane.setPage(ResourceLoader.getURLforDataFile(file));
m_scrollPane.getViewport().add(m_editorPane);
m_scrollPane.validate();
m_scrollPane.repaint(); <-- does not seem to solve this
add(m_scrollPane);
/// add( m_editorPane) <-- this WORKS !!
SynchronousHTMLEditorKit is defined as:
public class SynchronousHTMLEditorKit extends HTMLEditorKit {
public Document createDefaultDocument(){
HTMLDocument doc = (HTMLDocument)(super.createDefaultDocument());
doc.setAsynchronousLoadPriority(-1); //do synchronous load
return doc;
}
Try moving the validate and repaint calls to the bottom, after the add, and call them on the container, not the scrollpane
add(m_scrollPane);
validate();
repaint();
What happens if you don't use a SynchronousHTMLEditorKit? Your code works perfectly for me without it.
Related
I'm trying to make a GUI for my game. I've tried various libraries and I've ended up with Nifty. I haven't found any useful tutorial and therefore I'm learning from code examples.
I want to display a simple Button, but it seems that my code is not working. I've tried setting background color of Panel which has been working. I have no idea why the Button is not displaying.
Here's what I have:
protected void prepareNifty(Nifty nifty) {
ScreenBuilder sb = new ScreenBuilder("start");
LayerBuilder lb = new LayerBuilder();
PanelBuilder pb = new PanelBuilder();
pb.control(new ButtonBuilder("btn1", "First Button!"){{
alignCenter();
valignCenter();
height("5%");
width("15%");
backgroundColor(Color.WHITE);
}});
pb.childLayoutCenter();
lb.childLayoutVertical();
lb.panel(pb);
sb.layer(lb);
nifty.addScreen("start", sb.build(nifty));
}
I should add I'm using Slick2D and my class extends NiftyBasicGame.
How can I display the Button and set it an absolute position?
You'll need to load the controls and the styles too when you want to use the default controls, like the Button control.
Try something like:
nifty.loadStyleFile("nifty-default-styles.xml");
nifty.loadControlFile("nifty-default-controls.xml");
new ScreenBuilder("start") {{
layer(new LayerBuilder("background") {{
backgroundColor("#f008");
childLayoutAbsolute();
control(new ButtonBuilder("showPopupButton", "SHOW") {{
x(SizeValue.px(100));
y(SizeValue.px(100));
interactOnClick("showPopup()");
}});
}});
}}.build(nifty);
nifty.gotoScreen("start");
Besides that, it might help to read the nifty-gui-the-manual-1.3.2.pdf
I am rendering some images that are layered in a JEditorPane. I've read that JEditorPane is pretty rocky at best, however I am hoping that this is an issue with either my HTML code or something else. Here's how my content looks in the browser:
And how it looks in a JScrollBar(JEditorPane):
The HTML code: http://pastebin.com/EixG3WLH
The Java code:
File f = new File("index.html");
JEditorPane jep = new JEditorPane(f.toURI().toURL());
JScrollPane sp = new JScrollPane(jep);
JFrame frame = new JFrame();
frame.add(sp);
jep.setEditable(false);
frame.setVisible(true);
frame.setSize(500, 500);
frame.setTitle(wpj.getParse().getTitle());
I'd really rather not use FlyingSaucer if this issue can be resolved in a JEditorPane!
You can do it... but it's not really simple... because JEditorPane doesn't have CSS absolute positioning... so, you must first at all, recognize if some element had the position:absolute or position:fixed attribute extending the ViewFactory, something like:
public class ExtendedHTMLEditorKit extends HTMLEditorKit{
//.... other code here
public class MyHTMLFactory extends HTMLFactory{
//other code here
#Override
public View create(Element elem) {
if (isLayered(elem)){ //it means, it has position attribute
return new PositionedView(elem);
}
else
return super.create(elem);
}
boolean isLayered(Element elem){
SimpleAttributeSet sas = new SimpleAttributeSet(elem);
StyleSheet styles = (HTMLDocument elem.getDocument).getStyleSheet();
Tag tag = element.getAttributes().getAttribute(AttributeSet.NameAttribute);
sas.addAttributes(styleSheet.getRule(tag, element));
return sas.isDefined("position")
&& !sas.getAttribute("position").toString().equalsIgnorecase("static");
}
}
}
In this case, we need then to build a correct view for your element... I don't know if you're only positioning images (in this case, it could be simple) or a lot of things... I can see on your code, you're using divs...
Let me explain more or less what I do: I've created a ComponentView, and returning as a component a new JEditorPane, where I put the innerCode of the original element... and after that, move it on correct position of parent editor...
To synchronize this is really dificult to allow edit, but if you only whant to use them to display, it must be more simple...
ok.. the view must be like:
public class PositionedView extends ComponentView{
private JEditorPane view;
private JEditorPane parent;
#Override
public Component createComponent(){
if (view == null){
view = new JEditorPane();
}
String innerText = dumpInnerText(getElement());
view.setText(innerText);
view.setLocation(getAbsoluteX(), getAbsoluteY());
parent.add(view);
}
#Override
public void setParent(View parent) {
if (parent != null) {
java.awt.Container host = parent.getContainer();
if (host != null && host instanceof JEditorPane) {
parent = (JEditorPane) host;
}
}
super.setParent(parent);
}
protected int getAbsoluteX() {
//search for the attribute left or right and calculate the position over parent
}
protected int getAbsoluteY(){
//search for the attribute top or bottom and calculate the position over parent
}
protected String dumpInnerText(Element element){
//there are several ways to do it, I used my own reader/writer,
//because I've need add special tags support...
}
}
I hope this helps you... Ah! there are another thing: if you do this, you must secure your view is not opaque, and it means, all the view elements, on the other case, you will have a blank rect for your elements.
Another thing, you maybe need to check for the correct dimension of the view... do as getAbsoluteX / getAbsoluteY to obtain width / height attributes.
JEditorPane is not so good with CSS absolute positioning. I think you are trying to achieve more with JEditorPane than it is capable of delivering.
I don't think this is a new issue. But it seems that there is an error that comes up whenever an ordered/unordered list in JTextPane (EditorKit -> HTMLEditorKit, Document -> HTMLDocument) is deleted from all the way down to the top using the backspace key. The following is the exception thrown from the getText () method of GlyphView.
Exception in thread "AWT-EventQueue-0" javax.swing.text.StateInvariantError: GlyphView: Stale view: javax.swing.text.BadLocationException: Invalid location
I can provide a SSCCE for this. But it is not very difficult to simulate. Just use a JTextPane with HTMLEditorKit and HTMLDOcument model set inside it. Either use the custom "InsertOrderedList" action or have some way to insert the string
<HTML><HEAD></HEAD><BODY><UL><LI></LI></UL></BODY></HTML>
which will result in the insertion of an ordered/unordered list inside the text pane.
The weird parts of this bug are as follows:
Once you start deleting the characters (and if you happen to have lines below the bulleted list), the characters will get deleted until you hit the last character of the last bullet item. Once you reach this, the caret just refuses to move up and the error from GlyphView gets thrown.
Sometimes what happens is that after you have deleted most of the characters - you still won't be able to delete the first bullet of the list. It just hangs on until you do a ctrl+a and then backspace.
I have seen these bugs in almost all Java based HTML editors available online except for JWebEngine, where this behavior is not present. Unfortunately JWebEngine is not open sourced and hence I can't take a peek inside their code to see as to how they have solved this problem.
My guess is that the notification that is coming from the HTML document model has some problem due to which the cursor positioning code is not working correctly. I have also searched the Sun bugs database to check if this particular issue has been raised but could not find any (though I have seen quite a few bugs which are very similar to this). Also I am very sure that someone must have noticed this before and must have brought it to the Swing team's attention.
Does anyone working with Swing (particularly text) part know as to if this issue has been raised with Sun or if there is any known workaround that has been found to mitigate the problem?
Though it is possible that the user is still able to delete the lists from the pane using the mouse selection, not having the option to do the same using the backspace key just seems very weird.
SSCCE is now attached. To repro the bug pls. follow the steps as shown in the attached fig.
Add a line of text. Then add 2/3 bullet items by clicking on the button above the text pane. Now place the caret at the end of the last char of the last bullet and keep on pressing the entire backspace key until all the chars get deleted.
Observed behavior: the last bullet will hang on (won't get deleted) and the exception will be thrown (as mentioned above)
Expected: No exception and the contents of the text pane should get cleared.
public class Test {
static final JFrame frame = new JFrame ();
static final JTextPane textPane = new JTextPane ();
static EditorKit kit;
static JButton listButton;
public static void createAndShowGUI () {
//Create frame
frame.setSize(400, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
//Customize text pane visual properties
textPane.setSize(300, 500);
textPane.setLocation(50, 50);
//customize text pane non visual properties
kit = new CustomEditorKit ();
textPane.setEditorKitForContentType("text/html", kit);
textPane.setContentType("text/html");
Action[] actions = ((HTMLEditorKit) kit).getActions();
Action action = null;
for (int i = 0; i < actions.length; i++) {
action = actions [i];
if (action.getValue(Action.NAME).equals("InsertUnorderedList")) {
break;
}
}
listButton = new JButton (action);
listButton.setText("List");
listButton.setSize(100, 20);
listButton.setLocation(100, 10);
listButton.setVisible(true);
/* Add button and text pane to frame */
frame.add(listButton);
frame.add(textPane);
}
public static void main(String[] args) {
try {
EventQueue.invokeAndWait(new Runnable () {
#Override
public void run() {
createAndShowGUI ();
}
});
} catch (InterruptedException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
static class CustomEditorKit extends HTMLEditorKit {
#Override
public Document createDefaultDocument () {
return new HTMLDocument (this.getStyleSheet());
}
}
}
I used this
action=new HTMLEditorKit.InsertHTMLTextAction("test", "<UL><LI><P>\n</P></LI></UL>", HTML.Tag.BODY, HTML.Tag.UL);
instead of default action in your example to provide correct structure.
Works fine for me. (Win 7, Java 1.6)
I'm new to GWT, and am struggling through my first Web page with it.
I've created 2 Composite Widgets - ListWidget and MaintenanceWidget. When I add them both to a FlowPanel, they both show up as they should. However, when I try to use a SplitLayoutPanel, depending on how I do it, either none of them show or only one of them shows.
Below is my code:
public MainPanel(){
list = new ListWidget();
maintenance = new MaintenanceWidget();
panel = new SplitLayoutPanel();
panel.addWest(list, 200);
panel.addNorth(maintenance, 250);
initWidget(panel);
}
In my entry point onModuleLoad() method, I create an instance of MainPanel and add it to the root pane.
With this code, I get a blank space in the west where the list should be, and the maintenance widget on the top with a horizontal splitter beneath it.
I've tried different configurations of the panel.add****() method, but nothing has gotten me the results I'm looking for.
Any ideas? Thanks!
Make sure you have a doctype declaration in your HTML template (for example, <!doctype html>), since SplitLayoutPanel requires browser to work in standards mode.
I found some sample code here that used a method that I hadn't seen before.
My code now reads as follows:
public MainPanel(){
list = new ListWidget();
maintenance = new MaintenanceWidget();
panel = new SplitLayoutPanel();
panel.setPixelSize(500, 400);
panel.addWest(list, 200);
panel.add(maintenance);
initWidget(panel);
}
And now it works. Thanks for your help!
If not mistaken, SpliLayoutPanel must be attached to the body of the document.
Try something like:
public void onModuleLoad() {
SplitLayoutPanel panel = new SplitLayoutPanel();
panel.addWest(new Label("WEST"), 50);
panel.addNorth(new Label("NORTH"), 50);
panel.addEast(new Label("EAST"), 50);
panel.addSouth(new Label("SOUTH"), 50);
panel.add(new Label("CONTENT HERECONTENT HERECONTENT HERECONTENT HERECONTENT HERECONTENT HERE"));
RootLayoutPanel.get().add(panel); //This gets the body element and attaches itself to it, then adds panel.
}
Shouldn't be too hard to apply it to your code.
I am trying to create a very simple chat window that simply has the ability to display some text, which I add to from time to time. However I get the following run time error when attempting to append text to the window:
java.lang.ClassCastException: javax.swing.JViewport cannot be cast to javax.swing.JTextPane
at ChatBox.getTextPane(ChatBox.java:41)
at ChatBox.getDocument(ChatBox.java:45)
at ChatBox.addMessage(ChatBox.java:50)
at ImageTest2.main(ImageTest2.java:160)
Here is the class to handle the basic operations:
public class ChatBox extends JScrollPane {
private Style style;
public ChatBox() {
StyleContext context = new StyleContext();
StyledDocument document = new DefaultStyledDocument(context);
style = context.getStyle(StyleContext.DEFAULT_STYLE);
StyleConstants.setAlignment(style, StyleConstants.ALIGN_LEFT);
StyleConstants.setFontSize(style, 14);
StyleConstants.setSpaceAbove(style, 4);
StyleConstants.setSpaceBelow(style, 4);
JTextPane textPane = new JTextPane(document);
textPane.setEditable(false);
this.add(textPane);
}
public JTextPane getTextPane() {
return (JTextPane) this.getComponent(0);
}
public StyledDocument getDocument() {
return (StyledDocument) getTextPane().getStyledDocument();
}
public void addMessage(String speaker, String message) {
String combinedMessage = speaker + ": " + message;
StyledDocument document = getDocument();
try {
document.insertString(document.getLength(), combinedMessage, style);
} catch (BadLocationException badLocationException) {
System.err.println("Oops");
}
}
}
If there is a simpler way to do this, by all means let me know. I only need the text to be of a single font type, and uneditable by the user. Aside from that, I just need to be able to append text on the fly.
You have two options:
Store the JTextPane in a member variable and return that inside getTextPane().
Modify getTextPane to return the JViewPort's view, like this
return (JTextPane) getViewport().getView();
See the Swing tutorials for more detail.
Also, as camickr (and the tutorials) pointed out, using add with a JScrollPane is incorrect. You should be either passing the component to the constructor or using setViewportView.
As a side note, I try not to subclass Swing components unless it's absolutely necessary (preferring composition over inheritance). But that's not particularly relevant to the question.
Don't extend a JScrollPane. You are NOT adding any functionality to it.
It looks like the basic problem is that your are trying to add the text pane to the scrollpane. This is not the way it works. You need to add the text pane to the viewport. The easy way to do this is:
JTextPane textPane = new JTextPane();
JScrollPane scrollPane = new JScrollPane( textPane );
or
scrollPane.setViewportView( textPane );
public JTextPane getTextPane() {
return (JTextPane) this.getComponent(0);
}
this.getComponent(0) is returning the ScrollPane's JViewPort, not your JTextPane. It can't be casted, and so you get your exception.