JTextPane set color specific word - java

It's thought that the solution has been defined already. I'd like to think so but unfortunately the results are the same trying yet a 3rd solution produced no change to the text color...
..
I'm trying to change the color of a certain word in a JTextPane (to red) to
show it's status. There are a number of examples and I've tried several but the end result is either the text remains unchanged or the entire text's color changes.
I will place a snippet of code here because the class is rather large
..
textPane = new JTextPane();
textPane.setFont(new Font("Arial", Font.PLAIN, 12));
..
String productName = "PC";
String vendorName = "DELL";
String statusOfProd = "OFF";
String theObject = "Product " + productName + " Vendor " + vendorName;
String taData = theObject + "\n";
textPane.setText(taData);
if (statusOfProd.equals("OFF")){
addColor2Pane(productName, Color.RED);
}
..
private void addColor2Pane(String value2Change, Color color2Use) {
String theData = textPane.getText();
int v2cIndex = theData.indexOf(value2Change);
int v2cLen = value2Change.length();
try {
textPane.getHighlighter().addHighlight(v2cIndex, v2cIndex + v2cLen,
new DefaultHighlighter.DefaultHighlightPainter(color2Use));
}
catch (BadLocationException e) {
e.printStackTrace();
}
}
..
// Attributes
protected JTextPane textPane;
public static String taData;
The result of the above method has no effect. If I change the "addColor2Pane"
method to below the result renders all text in the pane RED which is not what I'm trying to achieve.
..
private void addColor2Pane(String value2Change, Color color2Use) {
StyleContext sc = StyleContext.getDefaultSytleContext();
AttributeSet aSet = sc.addAttribute(sc.getEmptySet(),
StyleConstants.Foreground,
color2Use);
aSet = sc.addAttribute(aSet,
StyleConstants.FontFamily,
"Lucida Console");
aSet = sc.addAttribute(aSet,
StyleConstants.Alignment,
StyleConstants.ALIGN_LEFT);
int v2cInd = theData.indexOf(value2Change);
int v2cLen = value2Change.length();
textPane.setCaretPosition(v2cInd);
textPane.setCharacterAttributes(aSet, true);
textPane.replaceSection(value2Change);
}
The desired result is ONLY have the color of the productName set to RED. Suggestions?

Related

itext 7 pdf how to prevent text overflow on right side of the page

I am using itextpdf 7 (7.2.0) to create a pdf file. However even though the TOC part is rendered very well, in the content part the text overflows. Here is my code that generates the pdf:
public class Main {
public static void main(String[] args) throws IOException {
PdfWriter writer = new PdfWriter("fiftyfourthPdf.pdf");
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf, PageSize.A4,false);
//document.setMargins(30,10,36,10);
// Create a PdfFont
PdfFont font = PdfFontFactory.createFont(StandardFonts.TIMES_ROMAN,"Cp1254");
document
.setTextAlignment(TextAlignment.JUSTIFIED)
.setFont(font)
.setFontSize(11);
PdfOutline outline = null;
java.util.List<AbstractMap.SimpleEntry<String, AbstractMap.SimpleEntry<String, Integer>>> toc = new ArrayList<>();
for(int i=0;i<5000;i++){
String line = "This is paragraph " + String.valueOf(i+1)+ " ";
line = line.concat(line).concat(line).concat(line).concat(line).concat(line);
Paragraph p = new Paragraph(line);
p.setKeepTogether(true);
document.add(p.setFont(font).setFontSize(10).setHorizontalAlignment(HorizontalAlignment.CENTER).setTextAlignment(TextAlignment.LEFT));
//PROCESS FOR TOC
String name = "para " + String.valueOf(i+1);
outline = createOutline(outline,pdf,line ,name );
AbstractMap.SimpleEntry<String, Integer> titlePage = new AbstractMap.SimpleEntry(line, pdf.getNumberOfPages());
p
.setFont(font)
.setFontSize(12)
//.setKeepWithNext(true)
.setDestination(name)
// Add the current page number to the table of contents list
.setNextRenderer(new UpdatePageRenderer(p));
toc.add(new AbstractMap.SimpleEntry(name, titlePage));
}
int contentPageNumber = pdf.getNumberOfPages();
for (int i = 1; i <= contentPageNumber; i++) {
// Write aligned text to the specified by parameters point
document.showTextAligned(new Paragraph(String.format("Sayfa %s / %s", i, contentPageNumber)).setFontSize(10),
559, 26, i, TextAlignment.RIGHT, VerticalAlignment.MIDDLE, 0);
}
//BEGINNING OF TOC
document.add(new AreaBreak());
Paragraph p = new Paragraph("Table of Contents")
.setFont(font)
.setDestination("toc");
document.add(p);
java.util.List<TabStop> tabStops = new ArrayList<>();
tabStops.add(new TabStop(580, TabAlignment.RIGHT, new DottedLine()));
for (AbstractMap.SimpleEntry<String, AbstractMap.SimpleEntry<String, Integer>> entry : toc) {
AbstractMap.SimpleEntry<String, Integer> text = entry.getValue();
p = new Paragraph()
.addTabStops(tabStops)
.add(text.getKey())
.add(new Tab())
.add(String.valueOf(text.getValue()))
.setAction(PdfAction.createGoTo(entry.getKey()));
document.add(p);
}
// Move the table of contents to the first page
int tocPageNumber = pdf.getNumberOfPages();
for (int i = 1; i <= tocPageNumber; i++) {
// Write aligned text to the specified by parameters point
document.showTextAligned(new Paragraph("\n footer text\n second line\nthird line").setFontColor(ColorConstants.RED).setFontSize(8),
300, 26, i, TextAlignment.CENTER, VerticalAlignment.MIDDLE, 0);
}
document.flush();
for(int z = 0; z< (tocPageNumber - contentPageNumber ); z++){
pdf.movePage(tocPageNumber,1);
pdf.getPage(1).setPageLabel(PageLabelNumberingStyle.UPPERCASE_LETTERS,
null, 1);
}
//pdf.movePage(tocPageNumber, 1);
// Add page labels
/*pdf.getPage(1).setPageLabel(PageLabelNumberingStyle.UPPERCASE_LETTERS,
null, 1);*/
pdf.getPage(tocPageNumber - contentPageNumber + 1).setPageLabel(PageLabelNumberingStyle.DECIMAL_ARABIC_NUMERALS,
null, 1);
document.close();
}
private static PdfOutline createOutline(PdfOutline outline, PdfDocument pdf, String title, String name) {
if (outline == null) {
outline = pdf.getOutlines(false);
outline = outline.addOutline(title);
outline.addDestination(PdfDestination.makeDestination(new PdfString(name)));
} else {
PdfOutline kid = outline.addOutline(title);
kid.addDestination(PdfDestination.makeDestination(new PdfString(name)));
}
return outline;
}
private static class UpdatePageRenderer extends ParagraphRenderer {
protected AbstractMap.SimpleEntry<String, Integer> entry;
public UpdatePageRenderer(Paragraph modelElement, AbstractMap.SimpleEntry<String, Integer> entry) {
super(modelElement);
this.entry = entry;
}
public UpdatePageRenderer(Paragraph modelElement) {
super(modelElement);
}
#Override
public LayoutResult layout(LayoutContext layoutContext) {
LayoutResult result = super.layout(layoutContext);
//entry.setValue(layoutContext.getArea().getPageNumber());
if (result.getStatus() != LayoutResult.FULL) {
if (null != result.getOverflowRenderer()) {
result.getOverflowRenderer().setProperty(
Property.LEADING,
result.getOverflowRenderer().getModelElement().getDefaultProperty(Property.LEADING));
} else {
// if overflow renderer is null, that could mean that the whole renderer will overflow
setProperty(
Property.LEADING,
result.getOverflowRenderer().getModelElement().getDefaultProperty(Property.LEADING));
}
}
return result;
}
#Override
// If not overriden, the default renderer will be used for the overflown part of the corresponding paragraph
public IRenderer getNextRenderer() {
return new UpdatePageRenderer((Paragraph) this.getModelElement());
}
}
}
Here are the screen shots of TOC part and content part :
TOC :
Content :
What am I missing? Thank you all for your help.
UPDATE
When I add the line below it renders with no overflow but the page margins of TOC and content part differ (the TOC margin is way more than the content margin). See the picture attached please :
document.setMargins(30,60,36,20);
Right Margin difference between TOC and content:
UPDATE 2 :
When I comment the line
document.setMargins(30,60,36,20);
and set the font size on line :
document.add(p.setFont(font).setFontSize(10).setHorizontalAlignment(HorizontalAlignment.CENTER).setTextAlignment(TextAlignment.LEFT));
to 12 then it renders fine. What difference should possibly the font size cause for the page content and margins? Are not there standard page margins and page setups? Am I unknowingly (I am newbie to itextpdf) messing some standard implementations?
TL; DR: either remove setFontSize in
p
.setFont(font)
.setFontSize(12)
//.setKeepWithNext(true)
.setDestination(name)
or change setFontSize(10) -> setFontSize(12) in
document.add(p.setFont(font).setFontSize(10).setHorizontalAlignment(HorizontalAlignment.CENTER).setTextAlignment(TextAlignment.LEFT));
Explanation: You are setting the Document to not immediately flush elements added to that document with the following line:
Document document = new Document(pdf, PageSize.A4,false);
Then you add an paragraph element with font size equal to 10 to the document with the following line:
document.add(p.setFont(font).setFontSize(10).setHorizontalAlignment(HorizontalAlignment.CENTER).setTextAlignment(TextAlignment.LEFT));
What happens is that the element is being laid out (split in lines etc), but now drawn on the page. Then you do .setFontSize(12) and this new font size is applied for draw only, so iText calculated that X characters would fit into one line assuming the font size is 10 while in reality the font size is 12 and obviously fewer characters can fit into one line.
There is no sense in setting the font size two times to different values - just pick one value you want to see in the resultant document and set it once.

JavaFX allow user only to edit certain areas of text

I'm designing a custom XML view with javafx.
Imagine the following XML.
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
Now I want the user to be able to edit the title, the artist etc. without him being able to change the rest of the XML.
Note that my goal is to achieve this with XML style and dont present the user with a input, dialog.
Any ideas how I can achieve this?
You could use a TextFormatter with a regex-filter to ensure the format:
This is just a small example: (You should adapt the regex to your needs)
TextArea ta = new TextArea();
ta.setText("<CD>\n <TITLE>Empire Burlesque</TITLE>\n <ARTIST>Bob Dylan</ARTIST>\n <COUNTRY>USA</COUNTRY>\n <COMPANY>Columbia</COMPANY>\n <PRICE>10.90</PRICE>\n <YEAR>1985</YEAR>\n</CD>");
UnaryOperator<Change> filter = c -> {
if(c.getControlNewText().matches("<CD>\\n <TITLE>.*</TITLE>\\n <ARTIST>.*</ARTIST>\\n <COUNTRY>.*</COUNTRY>\\n <COMPANY>.*</COMPANY>\\n <PRICE>[0-9]*\\.?[0-9]*</PRICE>\\n <YEAR>[0-9]{0,4}</YEAR>\\n</CD>")) {
return c;
}
// The new input doesn't match the regex and gets discarded
return null;
};
ta.setTextFormatter(new TextFormatter<String>(filter));
You could a layout for the xml on your own that uses Text nodes for the start/end tags and TextFields for the text content:
String input = "<CD>\n"
+ " <TITLE>Empire Burlesque</TITLE>\n"
+ " <ARTIST>Bob Dylan</ARTIST>\n"
+ " <COUNTRY>USA</COUNTRY>\n"
+ " <COMPANY>Columbia</COMPANY>\n"
+ " <PRICE>10.90</PRICE>\n"
+ " <YEAR>1985</YEAR>\n"
+ "</CD>";
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
inputFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
XMLStreamReader reader = inputFactory.createXMLStreamReader(new ByteArrayInputStream(input.getBytes()));
List<List<Node>> currentChildren = new ArrayList<>();
currentChildren.add(new ArrayList<>(1));
String text = null;
int depth = 0;
final Insets insets = new Insets(0, 0, 0, 20);
boolean hasChildren = false;
while (reader.hasNext()) {
switch (reader.next()) {
case XMLStreamConstants.START_ELEMENT:
depth++;
hasChildren = false;
currentChildren.add(new ArrayList<>());
break;
case XMLStreamConstants.CHARACTERS:
text = reader.getText();
break;
case XMLStreamConstants.END_ELEMENT:
String suffix = reader.getName().getLocalPart() + ">";
if (hasChildren) {
// element group
VBox vbox = new VBox(new Text("<" + suffix));
for (Node n : currentChildren.get(depth)) {
VBox.setMargin(n, insets);
}
vbox.getChildren().addAll(currentChildren.get(depth));
vbox.getChildren().add(new Text("</" + suffix));
currentChildren.get(depth - 1).add(vbox);
} else {
// text element
TextField textField = new TextField(text);
textField.setMinWidth(Region.USE_PREF_SIZE);
textField.setMaxWidth(Region.USE_PREF_SIZE);
// keep size of TextField large enough to contain all the text
ChangeListener<String> listener = new ChangeListener<String>() {
private final Text measureElement = new Text();
{
measureElement.setFont(Font.font("monospaced"));
}
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
measureElement.setText(newValue);
textField.setPrefWidth(measureElement.getLayoutBounds().getWidth() + 2);
}
};
listener.changed(null, null, text);
textField.textProperty().addListener(listener);
HBox hbox = new HBox(new Text('<' + suffix), textField, new Text("</" + suffix));
currentChildren.get(depth - 1).add(hbox);
hasChildren = true;
text = null;
}
currentChildren.remove(depth);
depth--;
break;
}
}
VBox root = (VBox) currentChildren.get(0).get(0);
root.getStyleClass().add("xml-editor");
CSS Stylesheet
.xml-editor .text-field,
.xml-editor .text-field:focused {
/* remove TextField border & background */
-fx-focus-color: transparent;
-fx-control-inner-background: transparent;
-fx-faint-focus-color: transparent;
-fx-text-box-border: transparent;
-fx-text-fill: black;
-fx-padding: 0;
-fx-font-family: 'monospaced';
}
.xml-editor Text {
-fx-font-family: 'monospaced';
}
You could achieve this by using the TextFlow component.
It works by passing objects to your TextFlow such as TextField, Text etc.
You can add custom styling to each of these objects.
Now, your XML titles could be Text objects for example and your values TextField ones.
Then, you could choose whether a TextField object you are adding to the TextFlow is editable or not. For example:
Text field = new Text("one");
TextField value = new TextField("two");
value.setPrefWidth(value.getText().length()*12); // customize if needed
value.setStyle("-fx-fill: RED;-fx-font-weight:normal;"); // adding css
value.setEditable(false); // this field cannot be edited
textFlow.getChildren().addAll(field,value);

Loading images and data from a text file and appending to it (Java)

I've created a platform game where each type of game object is assigned to specific rgb values so I can create levels by drawing them out in paint and loading the image. Right now I have the first two levels already loaded and I am able to get the path of the 3rd level through a textfield input and load a custom 3rd level. Each level needs a path to the png image of the level, and the number of coins needed to progress to the next level. I want to have every level load up from one text file where each line maybe has the level number, the image path, and the # of coins. I'm making it to be customizable so that the user can add or change levels simply by adding these parameters through 3 textfields in my customize menu. This way also my designer can help create levels and by reading from the text file I imagine there will be a lot less code in the long run when there are 20+ levels. Any ideas on how I can load from and append to this file? Here's what I'm working with right now:
public static BufferedImageLoader loader = new BufferedImageLoader();
public Handler(Camera cam){
this.cam = cam;
level1 = loader.loadImage("/level1.png");
level2 = loader.loadImage("/level2.png");
}
public void changeLevel(){
clearLevel();
cam.setX(0);
Player.coinCount = 0;
if(Game.LEVEL == 1){
Player.maxCoins = 4;
LoadImageLevel(level1);
}
if(Game.LEVEL == 2){
LoadImageLevel(level2);
Player.maxCoins = 11;
}
if(Game.LEVEL == 3){
System.out.println(Data.levelPath);
try{
level3 = loader.loadImage(Data.levelPath);
LoadImageLevel(level3);
} catch (Exception e) {
e.printStackTrace();
System.out.println("error loading custom level");
}
}
}
public Menu(Game game, Handler handler){
this.handler = handler;
pathField = new JTextField(10);
levelField = new JTextField(10);
coinField = new JTextField(10);
if(Game.gameState == STATE.Menu){
int selection = JOptionPane.showConfirmDialog(
null, getPanel(), "Input Form : "
, JOptionPane.OK_CANCEL_OPTION
, JOptionPane.PLAIN_MESSAGE);
if(selection == JOptionPane.OK_OPTION) {
Data.levelPath = pathField.getText();
Data.level = levelField.getText();
Data.coinAmount = Double.valueOf(coinField.getText());
System.out.println(Data.levelPath + Data.level + Data.coinAmount);
}
}
private JPanel getPanel(){
JPanel basePanel = new JPanel();
basePanel.setOpaque(true);
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new GridLayout(3, 2, 5, 5));
centerPanel.setBorder(
BorderFactory.createEmptyBorder(5, 5, 5, 5));
centerPanel.setOpaque(true);
JLabel mLabel1 = new JLabel("Enter path: (e.g., /level1.png) ");
JLabel mLabel2 = new JLabel("Enter which level to load the image in: ");
JLabel mLabel3 = new JLabel("Enter the amount of coins you must collect");
centerPanel.add(mLabel1);
centerPanel.add(pathField);
centerPanel.add(mLabel2);
centerPanel.add(levelField);
centerPanel.add(mLabel3);
centerPanel.add(coinField);
basePanel.add(centerPanel);
return basePanel;
}
Any ideas or suggestions are appreciated!
It's actually just....
Given a value of the input.getText() as 1#path#20, It have level number, the image path, and the number of coins separated by # token.
public static String [] separateFields(String input, String separator){
String[] separatedValues = input.split("#");
return separatedValues;
}
Call the function, define the arguments.
// input is textfield.getText() , and the value of input is 1#path#20
String [] result= separateFields(input, "#");
Then you get
int level = Integer.parseInt(result[0]); // level
String aPath = result[1]; // path
int numCoins = Integer.parseInt(result[2]); // number of coins

How to make it looking good sentence for line spacing

I develop some project, it works for tagging a words when i drag the words and click special button.
I want to make tags surrounding a word (begin & end tags with red color) (please refer exam picture, this)
but when it tagged at begin & end of text, it take null-spaces (like picture 2nd).
when I drag that spaces, there's no real space(white space or " " or "\nbsp" - no, never), that's just null space!
I can't select that space!
Pic. Link here
here's my code below:
attribute:
static final Color TAG_COLOR = new Color(255, 50, 50);
static final Color PLAIN_TXT_COLOR = new Color(0, 0, 0);
public static SimpleAttributeSet plainAttr = new SimpleAttributeSet();
public static SimpleAttributeSet tagAttr = new SimpleAttributeSet();
StyleConstants.setAlignment(plainAttr, StyleConstants.ALIGN_JUSTIFIED);
StyleConstants.setForeground(plainAttr, PLAIN_TXT_COLOR);
StyleConstants.setFontSize(plainAttr, 11);
StyleConstants.setBold(plainAttr, false);
StyleConstants.setAlignment(tagAttr, StyleConstants.ALIGN_JUSTIFIED);
StyleConstants.setForeground(tagAttr, TAG_COLOR);
StyleConstants.setFontSize(tagAttr, 11);
StyleConstants.setBold(tagAttr, true);
tagging function:
public static void tag_functiont() {
String taggedName = "tagMark";
int start_sel = mainEditText.getSelectionStart();
int end_sel = mainEditText.getSelectionEnd();
String selected = mainEditText.getSelectedText();
StyledDocument doc = mainEditText.getStyledDocument();
if(selected == null || selected.isEmpty()) return;
try {
String bTag = "__B:"+taggedName+"__";
String eTag = "__E:"+ taggedName +"__";
doc.insertString(start_sel, bTag, tagAttr);
doc.insertString(start_sel+bTag.length()+selected.length(), eTag, tagAttr);
} catch (Exception e) {
e.printStackTrace();
}
}
I also worked all possibility of attributes options.
(some kinds of fonts, all kinds of arrangement;center, right, left, justified )
could someone gimme a piece of advice???
Solved
I added " textPane.setContentType("html/text"); in main source, so foolish.
it triggered <p> & <div> tags.. so the paragraph are gone bad.

How to append result into JTextArea in another java class?

I have 2 separate java files (Main & RSS). I would like to return the result from my RSS class to my Main class. Right now the results are displayed in console. How can I append the results to my JTextArea instead? Thanks!
In my Main class:
public void news()
{
news = new JPanel();
news.setLayout( null );
JTextArea textArea = new JTextArea();
textArea.setBackground(SystemColor.window);
textArea.setBounds(10, 11, 859, 512);
textArea.setWrapStyleWord(true);
news.add(textArea);
TextSamplerDemo reader = TextSamplerDemo.getInstance();
reader.writeNews();
}
In my RSS class:
public void writeNews(){
try{
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
URL u = new URL("http://rss.cnn.com/rss/cnn_world.rss");
Document doc = builder.parse(u.openStream());
NodeList nodes = doc.getElementsByTagName("item");
for(int i=0;i<nodes.getLength();i++){
Element element = (Element)nodes.item(i);
System.out.println("Title: " + getElementValue(element,"title"));
System.out.println("Link: " + getElementValue(element,"link"));
}
}
catch(Exception ex){
ex.printStackTrace();
}
}
If you modify your RSS.writeNews method to return the parsed RSS feed, the Main class can easily insert the data into the text area.
// In the RSS class
public String writeNews()
{
String result = "";
...
// Instead of printing to console, store text in a String variable
result += "Title: " + getElementValue(element,"title");
result += "Link: " + getElementValue(element,"link");
...
// Return result
return result
}
// In the Main.news method
String rssNews = reader.writeNews();
textArea.append(rssNews);
Instead of initializing the text area in your method, initialize it globally (like your news var), then use
Main.textArea.setText(String text);
You could consider the Observer Design Pattern. This way, you don't have to share the JTextArea object between classes.

Categories