I'm using JEditorPane
to do code correction in my "game builder", which helps create maps for my another game.
(This then internally uses HTMLEditorKit
. Inline CSS and <div>
is used for formatting)
I wish to obtain the visual effect like an IDE:
[EXPECTED] (My StackOverflow rank is too low to post an image here)
Yet, the actual effect is: [ACTUAL]
Below is my code:
(in which strl[i]
is the ith substring, which will be syntactically correct. If there exist more than one possible functions that matches the partly-inputted string, then in strl[i]
, all of them will be stored in the same string, separated by $$
)
...(some code related to IDE functionalities)...
String txt = "";
for(int i = 0; i < strl.length; i++){
String[] list; boolean cont = strl[i].contains("$$");
if(cont) {
list = strl[i].split("\\$\\$");
txt += "<table style=\"display:inline;vertical-align:top;\"><tr><td>";
}
else list = new String[]{strl[i]};
for(String elem : list){
switch(elem.charAt(0)){//assigning colours by the first character in the string
//error colour (red - orange)
case 'e': txt += "<span style=\"color:red;background-color:yellow;font-weight:bold;\">"; break;
//syntax component (green)
case 'g': txt += "<span style=\"color:green;font-weight:bold;\">"; break;
//recognized function (blue)
case 'b': txt += "<span style=\"color:blue;font-weight:bold;\">"; break;
//recognized function (cyan)
case 'c': txt += "<span style=\"color:cyan;font-weight:bold;\">"; break;
}
txt += elem.substring(elem.indexOf("|")+1);//you may interpret this as "getting the value of substring"
switch(elem.charAt(0)){
case 'e': case 'g': case 'b': case 'c':
txt += "</span>";
}
if(cont) txt += "<br>";
}
if(cont) txt += "</td></tr></table>";
}
if(tip.equals("<br><b>In this code:</b>")) tip += "<br>There is no syntax error.";
msg += txt + tip;
cmdaid.setText(msg); //cmdaid is the JEditorPane in question.
cmdaid.select(0,0);
For the input if:{hav
, the generated html string is:
<table style="display:inline;vertical-align:top;"><tr><td>
<span style="color:blue;font-weight:bold;">have</span><br><span style="color:blue;font-weight:bold;">haved</span><br>
</td></tr></table>
<span style="color:red;background-color:yellow;font-weight:bold;">}</span><br>
<b>In this code:</b><br>The "if"-"then"-"else" structure should be in the form of: "if:{...}then:{...}else:{...}"
which, in W3School's Tryit Editor, is shown correctly: https://www.w3schools.com/code/tryit.asp?filename=GSTCQD0WF5WK
This demonstrates that my code should be fine in HTML/CSS, yet it doesn't work as expected in JEditorPane
with settings:
JEditorPane cmdaid = new JEditorPane();
cmdaid.setEditable(false);
cmdaid.setOpaque(false);
cmdaid.setFont(new Font("Times New Roman", 0, 16));
cmdaid.setEditorKit(new HTMLEditorKit());
cmdaid.setPreferredSize(new Dimension(200, 100));
JScrollPane cmdp = new JScrollPane(cmdaid, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
Since other formatting are completely fine, I'd expect that there's no issue with the JEditorPane settings. Yet, the inline table cannot work as expected.
My question is, is there any way to solve the issue, or is it the intrinsic problem with the JEditorPane?
Though I think that when the question is answered, I might have already been developing another game :|
Still, thankyou in advance for your detailed explanations.
According to oracle documentations and comments in the question post, HTMLEditorKit supported by Java only supports HTML 3.2, which is a fairly primitive version. Some advanced CSS are not supported.
After reading the comments in the question post, I made following modifications:
txt = ""; ArrayList<String> txts = new ArrayList<String>(); int l = 0;
for(int i = 0; i < strl.length; i++){
String[] list; boolean cont = strl[i].contains("$$"); char ch = strl[i].charAt(0);
list = new String[]{strl[i].substring(strl[i].indexOf("|")+1)};
if(cont) list = list[0].split("\\$\\$");
switch(ch){
//error colour (red - orange)
case 'e': txt += "<span style=\"color:red;background-color:yellow;font-weight:bold;\">"; break;
//syntax component (green)
case 'g': txt += "<span style=\"color:green;font-weight:bold;\">"; break;
//recognized function (blue)
case 'b': txt += "<span style=\"color:blue;font-weight:bold;\">"; break;
//recognized function (cyan)
case 'c': txt += "<span style=\"color:cyan;font-weight:bold;\">"; break;
}
int maxl = -1;
for(String elem : list) if(elem.length() > maxl) maxl = elem.length();
txt += pad(list[0], maxl); l += maxl;
for(int I = 1; I < list.length; I++){
if(I <= txts.size()) txts.set(I-1, txts.get(I-1)+fpad(pad(list[I], maxl), l-txts.get(I-1).length()));
else txts.add(I-1, fpad(pad(list[I], maxl), l));
}
switch(ch){
case 'e': case 'g': case 'b': case 'c':
txt += "</span>";
}
}
if(tip.equals("<br><b>In this code:</b>")) tip += "<br>There is no syntax error.";
msg += txt + "<span style=\"color:blue;font-weight:bold;\">";
for(String subt : txts) msg += "<br>" + toHTML(subt);
msg += "</span>" + tip;
cmdaid.setText("<div style=\"font-family:monospace;\">"+msg+"</div>");
cmdaid.select(0,0);
with:
String fpad(String in, int l){return String.format("%1$" + l + "s", in);}
//does front padding from string in to string with length l
String pad(String in, int l){return String.format("%1$-" + l + "s", in);}
//does right padding from string in to string with length l
String toHTML(String in){return in.replace(" ", " ");}
//transform string to HTML form, as HTML eats multiple adjacent whitespaces
I added another array to store the extra string recommendations, and the problem is resolved (see [NOW]). I used monospacing
to ensure regular spacing between characters, although more complex FontRenderingContext
can be used, I'd prefer keeping it simple for this (perhaps minor) component in my application.
[Case Closed]