Remove Leading from the first Paragraph on every page itext 7 java - java

I need to remove Leading property in first Paragrapg on every page(FixedLeading)?
PdfDocument pdf = new PdfDocument(new PdfWriter(DEST));
Document document = new Document(pdf);
setGridForFirstPage(pdf);
document.setMargins(0, 25, 25, 25);
String line = "Hello! Welcome to iTextPdf";
Paragraph el = new Paragraph(line);
Div div = new Div();
for (int i = 0; i < 30; i++) {
Paragraph element = new Paragraph();
element.add(line + " " + i);
element.setFixedLeading(130);
div.add(element);
}
LayoutResult result = div.createRendererSubTree().setParent(document.getRenderer()).layout(new LayoutContext(new LayoutArea(0, document.getPdfDocument().getDefaultPageSize())));
LayoutResult savePageResult = null;
deleteProperties(result);
savePageResult = div.createRendererSubTree().setParent(document.getRenderer()).layout(new LayoutContext(new LayoutArea(0, document.getPdfDocument().getDefaultPageSize())));
LayoutResult nextPageResult = savePageResult.getOverflowRenderer().layout(new LayoutContext(new LayoutArea(3, document.getPdfDocument().getDefaultPageSize())));
deleteProperties(nextPageResult);
document.add(div);
document.close();
}
private static void deleteProperties(LayoutResult childRendererListParagraph) {
List<IRenderer> childRenderers = childRendererListParagraph.getSplitRenderer().getChildRenderers();
for (int j = 0; j < childRenderers.size(); j++) {
IRenderer iRendererList = childRenderers.get(j);
if (j == 0) {
if (iRendererList != null && iRendererList.getModelElement().hasProperty(33)) {
iRendererList.getModelElement().deleteOwnProperty(33);
}
}
}
}
Its works only two page, i try using a loop, but it didn't work out

Your approach seems plausible: I imagine it could be improved by looping through all the overflow renderers (perhaphs, I will try it out and update the answer someday).
However, there is quite a different approach, which for me seems to be more convenient and accurate: why not to override ParagraphRenderer, so that leading is reset each time the corresponding Paragraph can not fit a page (and hence will be moved to the next page).
This is how such an extension class may look:
class CustomParagraphRenderer extends ParagraphRenderer {
public CustomParagraphRenderer(Paragraph modelElement) {
super(modelElement);
}
#Override
public LayoutResult layout(LayoutContext layoutContext) {
LayoutResult result = super.layout(layoutContext);
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 CustomParagraphRenderer((Paragraph) this.getModelElement());
}
}
Some points which I want to emphasize:
one should always override getNextRenderer in such cases, otherwise the default renderer will be used for the overflown part
it is better not to update the properties of the model element as you do, since in case you want to reuse the pararaph the initial properties will have been already gone. On the contrary, one should update the properties of the renderer itself (its properties have priority over the model element's, i.e. the paragraph's, ones)
And this is how you can use such a class. The only differences from your code are that:
setNextRenderer is called, so that your paragraph gets asociated with a custom renderer
leading for the first element is not set
doc.setMargins(0, 25, 25, 25);
String line = "Hello! Welcome to iTextPdf";
Div div = new Div();
for (int i = 0; i < 30; i++) {
Paragraph element = new Paragraph();
element.setNextRenderer(new CustomParagraphRenderer(element));
element.add(line + " " + i);
if (0 != i) {
element.setFixedLeading(130);
}
div.add(element);
}
And this is how the resultant PDF looks:

Related

event underline with many Text element itext7

I need extends TextRenderer for custom underline, but in one element Text i have one letter.
I have Large text and do this:
String s = "d < like to filter > RENDER_TEXT events as they are <written> to an output file. I have a <PDF that has some text in it> that I want filtered out. I've found that I can walk the document once and determine the characteristics of the render events that I want to filter. Now I'd like to copy the pages of the source document and skip over some RENDER_TEXT events so that the text does not appear in the destination document. I have an IEventFilter that will accept the correct events. I just need to know how to put this filter on the document writer.";
String[] words = s.split("");
Paragraph paragraph = new Paragraph();
Text text = null;
boolean isUnderStart = false;
boolean isUnderEnd = false;
int i = 1;
for (String word : words) {
if (word.equals("<")) {
isUnderStart = true;
}
if (word.equals(">")) {
isUnderEnd = true;
}
text = new Text(word);
text.setNextRenderer(new Word25TextRenderer(text, isUnderStart,isUnderEnd));
isUnderStart = false;
isUnderEnd = false;
paragraph.add(text);
i++;
}
doc.add(paragraph);
doc.close();
"<" и ">" i do for test (In a real program, I do to use Jsoup)
With help this symbols i find out coordinate axes for first simbol and end simbol. This is needed to draw the canvas element(line, curveTo). Also i add boolean to draw two times, the coordinates for the first letter and for the second.
Everything word for one line, if I want to draw underline for two line it does not break. In this part: <PDF that has some text in it>
static class Word25TextRenderer extends TextRenderer {
private boolean isUnderStart;
private boolean isUnderEnd;
public Word25TextRenderer(Text textElement, boolean isUnderStart, boolean isUnderEnd) {
super(textElement);
this.isUnderStart = isUnderStart;
this.isUnderEnd = isUnderEnd;
}
#Override
public IRenderer getNextRenderer() {
return new Word25TextRenderer((Text) modelElement, isUnderStart, isUnderEnd);
}
#Override
public void draw(DrawContext drawContext) {
super.draw(drawContext);
Rectangle textRect = getOccupiedAreaBBox();
int pageNumber = getOccupiedArea().getPageNumber();
PdfCanvas canvas = drawContext.getCanvas();
if (isUnderStart) {
canvas
.saveState()
.setStrokeColor(DeviceRgb.RED)
.moveTo(textRect.getRight(), textRect.getBottom());
}
if (isUnderEnd) {
canvas.curveTo(textRect.getRight(), textRect.getBottom() + textRect.getHeight() / 2,
textRect.getRight(), textRect.getBottom(),
textRect.getRight(), textRect.getBottom())
.stroke()
.restoreState();
}
}
}
Maybe you know other way?
Here's what happened in the end
p.s:I add one element to the text, because then I change the elements individually (font, fontSize etc) It's necessary!
Instead of doing the underlining at the Text element / renderer level, it's much handier to do it at the level of the Paragraph, where all the information about line split is known, since you have to underline parts of a same Text that are placed on different lines.
We will create a CustomText class to store information about whether we want to underline that piece of text still (although we could have used setProperty on a regular Text element):
static class CustomText extends Text {
private boolean isUnderStart;
private boolean isUnderEnd;
public CustomText(String text, boolean isUnderStart, boolean isUnderEnd) {
super(text);
this.isUnderStart = isUnderStart;
this.isUnderEnd = isUnderEnd;
}
public boolean isUnderStart() {
return isUnderStart;
}
public boolean isUnderEnd() {
return isUnderEnd;
}
}
The meaty part is our custom ParagraphRenderer - we go over the lines, remember the last "open bracket", or the text chunk start defines the start of the text to be underlined, and then once we face the "closing bracket", or the text chunk that defines the end of the text we do the actual drawing for the whole region. Additionally, we take care of the splits by underlining the remaining part of the line if by the time we finished line inspection we still have our "open bracket". Here id the code:
static class CustomParagraphRenderer extends ParagraphRenderer {
public CustomParagraphRenderer(Paragraph modelElement) {
super(modelElement);
}
#Override
public IRenderer getNextRenderer() {
return new CustomParagraphRenderer((Paragraph) modelElement);
}
#Override
public void draw(DrawContext drawContext) {
super.draw(drawContext);
Rectangle lastRectStart = null;
for (int i = 0; i < lines.size(); i++) {
LineRenderer lineRenderer = lines.get(i);
boolean anyEventsThisLine = false;
for (IRenderer renderer : lineRenderer.getChildRenderers()) {
if (renderer.getModelElement() instanceof CustomText &&
(((CustomText) renderer.getModelElement()).isUnderEnd()
|| ((CustomText) renderer.getModelElement()).isUnderStart())) {
anyEventsThisLine = true;
if ((((CustomText) renderer.getModelElement()).isUnderEnd())) {
Rectangle endRect = renderer.getOccupiedArea().getBBox();
PdfCanvas canvas = drawContext.getCanvas();
canvas.saveState().setStrokeColor(ColorConstants.RED)
.moveTo(lastRectStart.getRight(), lastRectStart.getBottom())
.curveTo(endRect.getRight(), endRect.getBottom() + endRect.getHeight() / 2,
endRect.getRight(), endRect.getBottom(),
endRect.getRight(), endRect.getBottom())
.stroke().restoreState();
lastRectStart = null;
} else {
lastRectStart = renderer.getOccupiedArea().getBBox();
}
}
}
if (lastRectStart != null && !anyEventsThisLine) {
// Underline the whole line
PdfCanvas canvas = drawContext.getCanvas();
Rectangle lineRect = lineRenderer.getOccupiedArea().getBBox();
canvas.saveState().setStrokeColor(ColorConstants.RED)
.moveTo(lineRect.getLeft(), lineRect.getBottom())
.curveTo(lineRect.getRight(), lineRect.getBottom() + lineRect.getHeight() / 2,
lineRect.getRight(), lineRect.getBottom(),
lineRect.getRight(), lineRect.getBottom())
.stroke().restoreState();
}
if (lastRectStart != null) {
// Draw till end of line
Rectangle endRect = lineRenderer.getChildRenderers().get(lineRenderer.getChildRenderers().size() - 1)
.getOccupiedArea().getBBox();
PdfCanvas canvas = drawContext.getCanvas();
canvas.saveState().setStrokeColor(ColorConstants.RED)
.moveTo(lastRectStart.getRight(), lastRectStart.getBottom())
.curveTo(endRect.getRight(), endRect.getBottom() + endRect.getHeight() / 2,
endRect.getRight(), endRect.getBottom(),
endRect.getRight(), endRect.getBottom())
.stroke().restoreState();
if (i + 1 < lines.size()) {
lastRectStart = lines.get(i + 1).getChildRenderers().get(0).getOccupiedArea().getBBox();
} else {
lastRectStart = null;
}
}
}
}
}
The main entry point code only has slight changes:
PdfDocument pdfDocument = new PdfDocument(new PdfWriter("C:/path/to.pdf"));
Document doc = new Document(pdfDocument);
String s = "d < like to filter > RENDER_TEXT events as they are <written> to an output file. I have a <PDF that has some text in it> that I want filtered out. I've found that I can walk the document once and determine the characteristics of the render events that I want to filter. Now I'd like to copy the pages of the source document and skip over some RENDER_TEXT events so that the text does not appear in the destination document. I have an IEventFilter that will accept the correct events. I just need to know how to put this filter on the document writer.";
String[] words = s.split("");
Paragraph paragraph = new Paragraph();
paragraph.setNextRenderer(new CustomParagraphRenderer(paragraph));
Text text = null;
boolean isUnderStart = false;
boolean isUnderEnd = false;
int i = 1;
for (String word : words) {
if (word.equals("<")) {
isUnderStart = true;
}
if (word.equals(">")) {
isUnderEnd = true;
}
text = new CustomText(word, isUnderStart, isUnderEnd);
isUnderStart = false;
isUnderEnd = false;
paragraph.add(text);
i++;
}
doc.add(paragraph);
doc.close();

Reference control by fx:id

I have a calendar screen I have designed for class using JavaFX and Scene Builder.
The part where I've placed the number is a label and the part that, currently, says "None", is a button. I want to reference the value in the Label when I select the Button so that I can display the Appointments for the user for that day.
Is there a way to reference a control by by the FX:ID string name so that I can do this? The Label is called lblDayOfTheWeekxx and the button is called btnAppointmentxx, where xx is the value from 01 to 42.
This is what I have tried for changing the value. It's just a test where I'm trying to turn the value of the first button to "DONE".
#FXML
void handleDayChosen(ActionEvent event) {
try {
// FXMLLoader loader = new FXMLLoader();
// loader.setLocation(getClass().getResource("/Views/FormMain.fxml"));
// Parent myView = loader.load();
// Scene myScene = new Scene(myView);
// Label lbl = (Label) myScene.lookup("#lblDateOfMonth01");
// Label myLblField = (Label)myView.FindControl("txtField" + 1);
// lbl.setText("DONE");
FXMLLoader loader = new FXMLLoader(getClass().getResource("/Views/FormMain.fxml"));
Parent root = loader.load();
Button foo = (Button)loader.getNamespace().get("lblAppointments01");
foo.setText("DONE");
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
I'm new to Java so I don't know what I'm doing wrong.
Thanks in advance,
Bill
This is what I finally came up with. I know it isn't pretty but it works.
GridPane gpCal = this.gpCalendar;
for (int i = 1 ; i <= 7; i++) {
int row = i * 2;
for (int col = 1; col <= 7; col++) {
int pos = ((i-1)*7)+col;
lblDay[pos] = new Label();
lblDay[pos].setText("");
lblDay[pos].setPrefSize(100, 20);
lblDay[pos].setText(String.valueOf(col) + ", " + String.valueOf(row));
gpCal.add(lblDay[pos], col, row);
}
row++;
for (int col = 0; col <= 6; col++) {
int pos = ((i-1)*7)+col;
btnAppts[pos] = new Button();
btnAppts[pos].setText("");
btnAppts[pos].setPrefSize(100, 100);
btnAppts[pos].setText(String.valueOf(col) + ", " + String.valueOf(row));
gpCal.add(btnAppts[pos], col, row);
}
}
Now for the easy part of formatting the buttons and labels to kind of match below.
Thanks for the help,
Bill
UIs like this do not lend themselves at all well to FXML. It is usually much easier, and way less code, to create a UI like this using Java. That way you can create the button and label in a loop, and add a different event handler to each:
int numDays = 30 ; // in real life this comes from the month and year
GridPane calendarPane = ...; // can be a #FXML-injected variable if needed
for (int i = 1 ; i <= numDays ; i++) {
Label dayLabel = new Label(Integer.toString(i));
Button button = new Button("None");
// set styles, etc
int day = i ;
button.setOnAction(e -> processButtonPress(button, dayLabel, day));
VBox vbox = new VBox(dayLabel, button);
int row = getRowForDay(i);
int col = getColumnForDay(i);
calendarPane.add(vbox, col, row);
}
// ...
private void handleDayChosen(Button button, Label label, int dayOfMonth) {
// whatever you need here...
label.setTextFill(Color.GREEN);
button.setText("Done");
}
Obviously you can still use FXML for the surrounding UI if you want, and just put the loop above in the controller's initialize() method. But this is clearly better than the 100+ lines of FXML plus 60 different variables in the controller to achieve the same thing.

How to Get Excel Data Validations Drop Down values for Referenced Cell Ranges

I have stumbled upon a problem when reading in an Excel document, specifically acquiring drop down values (Data Validation) from a Cells. I am able to get the values defined explicitly.
I am able to get the values (720x486, etc) with the following by seeing if cell is within CellRangeAddress.:
Map<CellRangeAddress, String[]> dropDownValues = new HashMap<>();
List<? extends DataValidation> dataValidations = sheet.getDataValidations();
for(DataValidation dataValidation : dataValidations)
{
for(CellRangeAddress cellRangeAddress : dataValidation.getRegions().getCellRangeAddresses())
{
String[] explicitListValues = dataValidation.getValidationConstraint().getExplicitListValues();
if(explicitListValues == null)
{
continue;
}
dropDownValues.put(cellRangeAddress, explicitListValues);
}
}
The code above works only for explicit values. The problem I see is when a range is defined in the source of the Data Validation for a cell:
sheet.getDataValidations();
Does not return anything in regards to the range or any info on the Data Validations. Has anyone been able to get a hold of the Source and evaluate the formula to attain values?
I was able to retrieve the data validations defined by a formula for Excel Sheets newer than 2003.
I had to parse the XSSFSheet for the specific info and then reconstruct and evaluate formula.
Here is what I did to attain all DataValidation values:
Map<CellRangeAddress, String[]> dropDownValues = new HashMap<>();
List<ExtendedDataValidations> extendedDataValidationsList = getExtendedDataValidations(sheet);
for (ExtendedDataValidations extendedDataValidations : extendedDataValidationsList)
{
AreaReference formulaReference = new AreaReference(extendedDataValidations.formula);
CellReference[] allReferencedCells = formulaReference.getAllReferencedCells();
FormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator();
String[] values = new String[allReferencedCells.length];
for (int j = 0; j < allReferencedCells.length; j++)
{
CellReference cellReference = allReferencedCells[j];
Sheet valueSheet = wb.getSheet(cellReference.getSheetName());
Cell cell = valueSheet.getRow(cellReference.getRow()).getCell(cellReference.getCol());
CellValue evaluate = formulaEvaluator.evaluate(cell);
values[j] = StringUtils.trimToEmpty(StringUtils.removeStart(StringUtils.removeEnd(evaluate.formatAsString(), "\""), "\""));
}
String stRef = extendedDataValidations.sqref;
String[] regions = stRef.split(" ");
for (String region : regions)
{
String[] parts = region.split(":");
CellReference begin = new CellReference(parts[0]);
CellReference end = parts.length > 1 ? new CellReference(parts[1]) : begin;
CellRangeAddress cellRangeAddress = new CellRangeAddress(begin.getRow(), end.getRow(), begin.getCol(), end.getCol());
dropDownValues.put(cellRangeAddress, values);
}
}
In addition I defined a Struc for the formula and cell reference.
private static class ExtendedDataValidations
{
public String formula;
public String sqref;
}
getExtendedDataValidations grabbed the CTExtensionList where the data validation forumla appeared in the sheet:
public static List<ExtendedDataValidations> getExtendedDataValidations(Sheet sheet)
{
List<ExtendedDataValidations> extendedDataValidationsList = new ArrayList<>();
if (sheet instanceof XSSFSheet)
{
CTExtensionList extLst = ((XSSFSheet) sheet).getCTWorksheet().getExtLst();
if (extLst == null)
{
return extendedDataValidationsList;
}
CTExtension[] extArray = extLst.getExtArray();
List<Node> dataValidationNodes = new ArrayList<>();
for (CTExtension anExtArray : extArray)
{
searchForDataValidation(anExtArray.getDomNode(), dataValidationNodes);
}
for (Node dataValidationNode : dataValidationNodes)
{
ExtendedDataValidations dataValidations = new ExtendedDataValidations();
getDataValidationInfo(dataValidationNode, dataValidations);
extendedDataValidationsList.add(dataValidations);
}
}
return extendedDataValidationsList;
}
searchForDataValidation had to traverse the DOM nodes of the sheet looking for specific info on DataValidation. If found Save it in List:
private static void searchForDataValidation(Node node, List<Node> nodesInQuestion)
{
if (StringUtils.equalsIgnoreCase("x14:dataValidation", node.getNodeName()))
{
nodesInQuestion.add(node);
return;
}
for (int i = 0; i < node.getChildNodes().getLength(); i++)
{
searchForDataValidation(node.getChildNodes().item(i), nodesInQuestion);
}
}
getDataValidationInfo was in charge of getting the formula and Cell Reference.
private static void getDataValidationInfo(Node node, ExtendedDataValidations dataValidations)
{
if (StringUtils.equalsIgnoreCase("#text", node.getNodeName()))
{
if (StringUtils.equalsIgnoreCase("xm:sqref", node.getParentNode().getNodeName()))
{
dataValidations.sqref = node.getNodeValue();
}
else if (StringUtils.equalsIgnoreCase("xm:f", node.getParentNode().getNodeName()))
{
dataValidations.formula = node.getNodeValue();
}
return;
}
for (int i = 0; i < node.getChildNodes().getLength(); i++)
{
getDataValidationInfo(node.getChildNodes().item(i), dataValidations);
}
}
Might appear to be complicated, but it does the trick. Hope it helps!

Java SWT show Line numbers for StyledText

I was wondering if there is a straightforward way to display line numbers with StyledText text field - even if lines are wrapped. I'm using it in my application and if content gets to big, some line numbers would be nice.
Thank you.
The key is org.eclipse.swt.custom.Bullet. It's basically a symbol (or in our case a number) you can add to the beginning of a line.
//text is your StyledText
text.addLineStyleListener(new LineStyleListener()
{
public void lineGetStyle(LineStyleEvent e)
{
//Set the line number
e.bulletIndex = text.getLineAtOffset(e.lineOffset);
//Set the style, 12 pixles wide for each digit
StyleRange style = new StyleRange();
style.metrics = new GlyphMetrics(0, 0, Integer.toString(text.getLineCount()+1).length()*12);
//Create and set the bullet
e.bullet = new Bullet(ST.BULLET_NUMBER,style);
}
});
This is my working implementation.
styledText.addLineStyleListener(new LineStyleListener() {
#Override
public void lineGetStyle(LineStyleEvent event) {
// Using ST.BULLET_NUMBER sometimes results in weird alignment.
//event.bulletIndex = styledText.getLineAtOffset(event.lineOffset);
StyleRange styleRange = new StyleRange();
styleRange.foreground = Display.getCurrent().getSystemColor(SWT.COLOR_GRAY);
int maxLine = styledText.getLineCount();
int bulletLength = Integer.toString(maxLine).length();
// Width of number character is half the height in monospaced font, add 1 character width for right padding.
int bulletWidth = (bulletLength + 1) * styledText.getLineHeight() / 2;
styleRange.metrics = new GlyphMetrics(0, 0, bulletWidth);
event.bullet = new Bullet(ST.BULLET_TEXT, styleRange);
// getLineAtOffset() returns a zero-based line index.
int bulletLine = styledText.getLineAtOffset(event.lineOffset) + 1;
event.bullet.text = String.format("%" + bulletLength + "s", bulletLine);
}
});
styledText.addModifyListener(new ModifyListener() {
#Override
public void modifyText(ModifyEvent e) {
// For line number redrawing.
styledText.redraw();
}
});
Note that the possible overhead of syntax highlighting recalculation when calling redraw() is likely to be acceptable, because lineGetStyle() are only called with lines currently on screen.
I believe that using a LineStyleListener should work. Something along the lines of:
styledText.addLineStyleListener(
new LineStyleListener() {
#Override
public void lineGetStyle(LineStyleEvent event) {
String line = event.lineText;
int lineNumber = event.lineOffset;
// Do stuff to add line numbers
}
}
);
This is a way to use bullets that updates the numbers when the content changes:
text.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent event) {
int maxLine = text.getLineCount();
int lineCountWidth = Math.max(String.valueOf(maxLine).length(), 3);
StyleRange style = new StyleRange();
style.metrics = new GlyphMetrics(0, 0, lineCountWidth * 8 + 5);
Bullet bullet = new Bullet(ST.BULLET_NUMBER, style);
text.setLineBullet(0, text.getLineCount(), null);
text.setLineBullet(0, text.getLineCount(), bullet);
}
});
As a side-note for colouring the line numbers:
Device device = Display.getCurrent();
style.background = new Color(device, LINE_NUMBER_BG);
style.foreground = new Color(device, LINE_NUMBER_FG);
where LINE_NUMBER_BG and LINE_NUMBER_FG might be a RGB object such as:
final RGB LINE_NUMBER_BG = new RBG(160, 80, 0); // brown
final RGB LINE_NUMBER_FG = new RGB(255, 255, 255); // white

In Java/Swing, is there a way to legally "attempt to mutate in notification"?

I was wondering if there is some sort of magic I can use to get around an IllegalStateException and allow a JTextField to "attempt to mutate in notification", or in other words to set its own text if its listener is triggered.
For your information, I am trying to program an auto-complete function which returns the most likely match in a range of 12 enums in response to a user's input in the JTextField.
Here is the code sample. You'll have to pardon my clumsy algorithm which creaks out enum results. I've highlighted the code which produces the exception with a comment:
jtfElement1.addCaretListener(new CaretListener() {
#Override
public void caretUpdate(CaretEvent e) {
String s = jtfElement1.getText();
int[] attributes = new int[13];
// iterate through each enum
for (BaseEnumAttributes b: BaseEnumAttributes.values()) {
// iterate through the length of the current text in jtfElement1
for (int i = 0; i < s.length(); i++) {
if (s.length() <= b.toString().length()) {
if (b.toString().charAt(i) == s.charAt(i)) {
// increase the number of "hits" noted for that enum
attributes[b.ordinal()] = attributes[b.ordinal()] + 1;
}
}
}
}
int priorC = 0;
int rightC = 0;
// iterate through the "array" of enums to find the highest score
for (int j = 0; j < attributes.length; j++) {
if (attributes[j] > priorC) {
priorC = attributes[j];
rightC = j;
}
}
if (!s.equals("")) {
// assign to b the Enum corresponding to the "array" with highest score
BaseEnumAttributes b = BaseEnumAttributes.values()[rightC];
iController.updateInputElement1String(b.toString());
// THIS TRIGGERS EXCEPTION
jtfElement1.setText(b.toString());
}
}
});
You are probably better off using a document filter or a custom document.
What are other listeners expected to see if the document doesn't stay the same during event dispatch?
Use SwingUtilities.invokeLater() placing all the modifications there
Maybe you can delay the setText() with a Thread to run after caretUpdate() has terminated.
i'm found on the same problem but i found an easy solution:
lock the caretUpdate() by a boolean if(false) while u'r setting the text to the jTextField than unlock it after . . something like this:
boolean caret = true;
private void listValueChanged(javax.swing.event.ListSelectionEvent evt) {
caret = false;
name.setText((String)list.getSelectedValue());
caret = true;
}
private void nameCaretUpdate(javax.swing.event.CaretEvent evt) {
if(caret){
model = new DefaultListModel();
this.fillList(name.getText());
list.setModel(model);
}
}
Create a custom Document and override insertString( )
filenameText = new JTextField(new FilenameDocument(), "", 0);
...
/**
* document which adds .xml extension if not specified
*
*/
private class FilenameDocument extends PlainDocument {
#Override
public void insertString(int offset, String insertedText, AttributeSet set)
throws BadLocationException {
if (offset == 0) {
insertedText = insertedText.trim( );
}
super.insertString(offset, insertedText, set);
if (filenameText != null) {
final int caretPos = filenameText.getCaretPosition();
String text = filenameText.getText().trim();
if (text.indexOf('.') == -1) {
filenameText.setText(text + ".xml");
filenameText.setCaretPosition(caretPos);
}
}
}
}
Note that calling setText will result in a recursive call to insertString( ), so make sure you have a stopping condition.
I'm surprised no one has answered this, but would'nt you have been better off implementing an editable JSpinner with a SpinnerListModel?

Categories