Good day. I'm building a simple pdf report using native PrintedPdfDocument class and I need to insert a text with hyperlink into a document. This is my simple implementation of pdf page.
PrintedPdfDocument document = new PrintedPdfDocument(context, attributes);
PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(595, 842, 1).create();
PdfDocument.Page page = document.startPage(pageInfo);
Canvas c = page.getCanvas();
TextPaint p = new TextPaint();
Here a several ways I had tried but still no luck.
First way using a Canvas drawText() method. Result: "some link" without hyperlink.
c.drawText("<a href='https://example.com'>some link</a>", 30, 30, p);
Second way using SpannableString. Result: "some link".
String link = "https://example.com";
SpannableString s = new SpannableString("some link");
s.setSpan(new URLSpan(link), 0, link.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
c.drawText(s.toString(), 30, 30, p);
Third way using StaticLayout. Result: blank space.
Spanned spanned = Html.fromHtml("<a href='https://example.com'>some link</a>", null, null);
StaticLayout l = new StaticLayout(spanned, p, 30, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
l.draw(c);
TextView do not draw anything to Canvas.
TextView tv = new TextView(context);
tv.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
tv.setText(Html.fromHtml("<a href='https://example.com'>some link</a>"));
tv.draw(c);
Maybe you better know how to deal with it?
Related
I'm using itext 7.1.9 and I need to create a PDF document with two checkbox fields with the same names.
A have tried it the next way:
PdfFormField field = PdfFormField.createComboBox(pdf, rect, name, value, options);
PdfFormField parent;
if ( (parent = form.getField(name)) != null) {
parent.addKid(field);
parent.setValue(value);
}
but it doesn't work for me. The fields disappeared from the PDF.
I used iText version 7.2.0 to create PDF where iText creates two fields with the same name. To see the result use Google Chrome or PDF Studio 2021. For some reason Acrobat doesn't render second field with the same name
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outPdf));
pdfDoc.addNewPage();
PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
PdfFormField field1 = PdfFormField.createComboBox(pdfDoc, new Rectangle(50, 730, 100, 20), "name", "value", new String[] {"one", "two"});
PdfFormField field2 = PdfFormField.createComboBox(pdfDoc, new Rectangle(50, 700, 100, 20), "name", "value", new String[] {"one", "two", "three"});
form.addField(field1);
form.addField(field2);
pdfDoc.close();
If you want to create checkbox fields with the same name use PdfFormField#createCheckbox method.
I'm making a notepad application using JavaFX which includes a font selector window. The font selector includes a textfield within a gridpane layout which functions as a sample of what the selected font options will look like.
Font selector:
However, if the font chosen is taller than the text field, the field stretches to fit the text, distorting the window.
Distorted font selector:
I want the sample textfield to remain the same size even if the text contained is taller than the field, like the font selector shown below:
I've tried using the 'setPrefSize' and 'setMaxSize' textfield methods to force a maximum height.
public static final String display(String savedFamily, String savedStyle, String savedSize, String stylesheet) {
fontFamily = savedFamily;
fontSize = savedSize.substring(0, savedSize.length() - 2);
fontWeight = getChosenWeight(savedStyle);
fontStyle = getChosenStyle(savedStyle);
// Add stage
Stage window = new Stage();
window.initModality(Modality.APPLICATION_MODAL);
TextField sample = new TextField("AaBbYyZz");
sample.setEditable(false);
sample.getStyleClass().add("sample");
sample.setAlignment(Pos.CENTER);
sample.setStyle(getCSS());
sample.setPrefSize(200, 60);
sample.setMaxHeight(60);
// Add list view title labels
Label fontLabel = new Label("Font:");
Label fontStyleLabel = new Label("Font Style:");
Label fontSizeLabel = new Label("Font Size: ");
// Add font list view
ListView<String> fontView = new ListView<>();
String fonts[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
for (int i = 0; i < fonts.length; i++) {
fontView.getItems().add(fonts[i]);
}
fontView.getSelectionModel().select(fontFamily);
fontView.setMaxSize(200, 150);
fontView.getSelectionModel().selectedItemProperty().addListener((v) -> {
fontFamily = fontView.getSelectionModel().getSelectedItem();
sample.setStyle(getCSS());
});
// Add font style list view
ListView<String> fontStyleView = new ListView<>();
fontStyleView.getItems().addAll("Regular", "Italic", "Bold", "Bold Italic");
fontStyleView.getSelectionModel().select(savedStyle);
fontStyleView.setMaxSize(80, 150);
fontStyleView.getSelectionModel().selectedItemProperty().addListener((v) -> {
fontStyle = getChosenStyle(fontStyleView.getSelectionModel().getSelectedItem());
fontWeight = getChosenWeight(fontStyleView.getSelectionModel().getSelectedItem());
sample.setStyle(getCSS());
});
// Add font size list view
ListView<String> fontSizeView = new ListView<>();
fontSizeView.getItems().addAll("6", "7", "8", "9", "10", "11", "12", "14", "16", "18", "20", "22", "24", "26", "28");
fontSizeView.getSelectionModel().select(fontSize);
fontSizeView.setMaxSize(80, 150);
fontSizeView.getSelectionModel().selectedItemProperty().addListener((v) -> {
fontSize = fontSizeView.getSelectionModel().getSelectedItem();
sample.setStyle(getCSS());
});
// Add OK button
Button okButton = new Button("OK");
okButton.setOnAction(e -> {
fontCssString = getCSS();
window.close();
});
// Add cancel button
Button cancelButton = new Button("Cancel");
cancelButton.setOnAction(e -> {
window.close();
});
// Add and configure grid pane
GridPane layout = new GridPane();
layout.setPadding(new Insets(15, 15, 15, 15));
layout.setVgap(20);
layout.setHgap(20);
// Set grid constraints for font list view and title
GridPane.setConstraints(fontLabel, 0, 0);
GridPane.setConstraints(fontView, 0, 1);
// Set grid constraints for font style list view and title
GridPane.setConstraints(fontStyleLabel, 1, 0);
GridPane.setConstraints(fontStyleView, 1, 1);
GridPane.setValignment(fontStyleView, VPos.TOP);
// Set grid constraints for font size list view and title
GridPane.setConstraints(fontSizeLabel, 2, 0);
GridPane.setConstraints(fontSizeView, 2, 1);
// Set grid constraints for sample title
GridPane.setConstraints(sample, 0, 2);
GridPane.setHalignment(sample, HPos.CENTER);
// set grid constraints and alignments for buttons
GridPane.setConstraints(okButton, 1, 2);
GridPane.setHalignment(okButton, HPos.RIGHT);
GridPane.setConstraints(cancelButton, 2, 2);
// Add items to grid pane layout
layout.getChildren().addAll(fontLabel, fontView, fontStyleLabel, fontStyleView, fontSizeLabel, fontSizeView,
sample, okButton, cancelButton);
// configure the scene and stage
Scene scene = new Scene(layout, 450, 300);
scene.getStylesheets().add(FontWindow.class.getResource(stylesheet).toExternalForm());
window.setScene(scene);
window.setTitle("Font Options");
window.showAndWait();
return fontCssString;
}
public static final String getChosenStyle(String s) {
String result = "normal";
if (s.contains("Italic")) {
result = "italic";
}
return result;
}
public static final String getChosenWeight(String s) {
String result = "normal";
if (s.contains("Bold")) {
result = "bold";
}
return result;
}
public static String getCSS() {
return "-fx-font-family: " + fontFamily + "; -fx-font-weight: " + fontWeight + "; -fx-font-style: " + fontStyle
+ "; -fx-font-size: " + Float.valueOf(fontSize) / 9.7 + "em;";
}
}
Edit: This has been solved! I was able to get the text field to function as I wanted by setting the maximum and minimum size as well as setting the preferred height and width to 'region.USE_COMPUTED_SIZE'.
This woks to me.
<TextField layoutX="151.0" layoutY="53.0" maxHeight="50.0" maxWidth="255.0" minHeight="50.0" minWidth="255.0" text="AaZz">
...and Pref Height/Pref Width are "USE_COMPUTED_SIZE"
All TextField has preferred padding in each side.
Tips: to change the TextField into the least size, make it sure change also the padding of the TextField to make the size you want.
in JavaFx:
TextField textDisplay = new TextField();
textDisplay.setPrefSize(100,5);
textDisplay.setPadding(new Insets(1,1,1,1));
if you want set the size of your textField base on the fontSize in textField ,just leave it a null "DONT USE" .setPrefSize(double,double); that will set the static size of your textField BUT set the max of your textfield using css/javafx
textDisplay.setMaxWidth(double);
textDisplay.setMaxHeiht(double);
or
textDisplay.setSize(double,double);
but if you use CSS much more easy to design your GUI just dont forget set an ID of your nodes.
textDisplay.setStyle("-fx-pref-width: 100"
+"\n-fx-pref-height: 100"
+"-fx-padding: 5 5 5 5;");
or
textDisplay.setId("idTextDisplay");
#idTextDisplay{
-fx-pref-width: 100;
-fx-pref-height: 100;
-fx-padding: 5 5 5 5;
}
in your case is:
TextField sample = new TextField("AaBbYyZz");
sample.setEditable(false);
sample.getStyleClass().add("sample");
sample.setAlignment(Pos.CENTER);
sample.setStyle(getCSS());
sample.setPrefSize(200, 60);
sample.prefHeight(Region.USE_COMPUTED_SIZE);
sample.prefwidth(Region.USE_COMPUTED_SIZE);
I'm having issues getting libgdxs scrollpane control to work. The code below shows control setup for a simple layout with a label, a List of items inside a scrollpane, and a button. The problem is my scroll pane doesn't show anything other than the vScroll/vScrollKnob ninepatch (that tiny white square)
it just looks like this:
screenshot.
private void setupLayout()
{
String[] listEntries = {"1","2","3","4","5"};
ListStyle listStyle = new ListStyle();
NinePatch example = new NinePatch(new Texture(Gdx.files.internal("data/example.9.png")));
listStyle.selectedPatch = example;
listStyle.font = new BitmapFont();
mList = new List(listEntries,listStyle);
ScrollPaneStyle paneStyle = new ScrollPaneStyle();
paneStyle.vScroll = example;
paneStyle.vScrollKnob = example;
mListScroll = new ScrollPane(mList,paneStyle);
mListScroll.setScrollingDisabled(true, false);
mListScroll.width = 500;
mListScroll.height = 500;
LabelStyle ls = new LabelStyle();
ls.font = new BitmapFont();
ls.fontColor = new Color(1.0f, 1.0f, 1.0f, 1.0f);
mLabel = new Label("Label", ls);
TextButtonStyle buttonStyle = new TextButtonStyle();
buttonStyle.font = new BitmapFont();
mButton = new TextButton("Button",buttonStyle);
Table table = new Table();
table.add(mLabel);
table.row();
table.add(mButton);
table.row();
table.add(mListScroll);
mStage.addActor(table);
}
It works as expected if i don't user the scroll pane and add the list directly to the table like this:
Table table = new Table();
table.add(mLabel);
table.row();
table.add(mButton);
table.row();
table.add(mList); //changed mListScroll(scrollpane class) to mList(List class)
mStage.addActor(table);
screenshot
But then it will extend out the bottom of my screen when there are too many items. What am I doing wrong here? Is there another parameter i need to set on the scrollpane?
I believe the issue you are having is how you are adding things to the table. I would suggest the following code instead of how you are doing it:
Table table = new Table();
table.add(mLabel);
table.row();
table.add(mButton);
table.row();
// Changing the table layout size itself.
table.add(mListScroll).size(500, 500);
mStage.addActor(table);
For more a more detailed explanation refer to TableLayout the quick start here shows you more how using tables for laying out objects.
Currently I am loading one tile data-layer over an OSMdroid basemap with
final MapTileProviderBasic tileProvider =
new MapTileProviderBasic(getApplicationContext());
final ITileSource tileSource =
new XYTileSource("MyCustomTiles", null, 1, 16, 256, ".png",
"http://a.url.to/custom-tiles/");
tileProvider.setTileSource(tileSource);
final TilesOverlay tilesOverlay =
new TilesOverlay(tileProvider, this.getBaseContext());
tilesOverlay.setLoadingBackgroundColor(Color.TRANSPARENT);
osmv.getOverlays().add(tilesOverlay);
Is it possible to render multiple data layers on top of each other over the BaseMap or can I only display one data layer at a time?
I found this example for GoogleMaps, but haven't found some example OSMdroid code dealing with multipe tileSources at a time.
Yes, of course you can. You just have to add another TilesOverlay to the map. The overlays(also tilesOverlays) get drawn consecutively, starting at the list's lowest index(=0).
Here's an example:
//create the first tilesOverlay
final MapTileProviderBasic tileProvider = new MapTileProviderBasic(getApplicationContext());
final ITileSource tileSource = new XYTileSource("MyCustomTiles", null, 1, 16, 256, ".png",
"http://a.url.to/custom-tiles/");
tileProvider.setTileSource(tileSource);
final TilesOverlay tilesOverlay = new TilesOverlay(tileProvider, this.getBaseContext());
tilesOverlay.setLoadingBackgroundColor(Color.TRANSPARENT);
//create the second one
final MapTileProviderBasic anotherTileProvider = new MapTileProviderBasic(getApplicationContext());
final ITileSource anotherTileSource = new XYTileSource("MyCustomTiles", null, 1, 16, 256, ".png",
"http://a.secondurl.to/custom-tiles/");
anotherTileProvider.setTileSource(anotherTileSource);
final TilesOverlay secondTilesOverlay = new TilesOverlay(anotherTileProvider, this.getBaseContext());
secondTilesOverlay.setLoadingBackgroundColor(Color.TRANSPARENT);
// add the first tilesOverlay to the list
osmv.getOverlays().add(tilesOverlay);
// add the second tilesOverlay to the list
osmv.getOverlays().add(secondTilesOverlay);
In my Swing application, users enter styled text into a JTextPane which uses an RTFEditorKit (HTML is also a possibility).
I then need to render many of these styled notes at specific coordinates in a custom component.
I would think the View.paint method would be helpful here, but I'm not able to create a usable View object.
I have the following method:
public View createView() throws IOException, BadLocationException {
RTFEditorKit kit = new RTFEditorKit();
final Document document = kit.createDefaultDocument();
kit.read(new ByteArrayInputStream(text.getBytes("UTF-8")), document, 0);
return kit.getViewFactory().create(document.getDefaultRootElement());
}
This returns a javax.swing.text.BoxView with the following attributes:
majorAxis = 1
majorSpan = 0
minorSpan = 0
majorReqValid = false
minorReqValid = false
majorRequest = null
minorRequest = null
majorAllocValid = false
majorOffsets = {int[0]#2321}
majorSpans = {int[0]#2322}
minorAllocValid = false
minorOffsets = {int[0]#2323}
minorSpans = {int[0]#2324}
tempRect = {java.awt.Rectangle#2325}"java.awt.Rectangle[x=0,y=0,width=0,height=0]"
children = {javax.swing.text.View[1]#2326}
nchildren = 0
left = 0
right = 0
top = 0
bottom = 0
childAlloc = {java.awt.Rectangle#2327}"java.awt.Rectangle[x=0,y=0,width=0,height=0]"
parent = null
elem = {javax.swing.text.DefaultStyledDocument$SectionElement#2328}"BranchElement(section) 0,35\n"
Note that parent = null and nchildren = 0. This means there's nothing really useful there. I can hack together something by calling JTextPane.getUI().paint, but the text pane needs to be visible, and this feels like the wrong way to do it.
Is there any way to get a visual representation of the RTF content without rendering the actual JTextPane?
This code sort of works, but seems less than ideal. Is there a better way to do it? Also, what's a good way to render the text somewhere other than 0,0 on the graphics?
private static void testRtfRender() {
String s = "{\\rtf1\\ansi\n" +
"{\\fonttbl\\f0\\fnil Monospaced;\\f1\\fnil Lucida Grande;}\n" +
"\n" +
"\\f1\\fs26\\i0\\b0\\cf0 this is a \\b test\\b0\\par\n" +
"}";
JTextPane pane = new JTextPane();
pane.setContentType("text/rtf");
pane.setText(s);
final Dimension preferredSize = pane.getUI().getPreferredSize(pane);
int w = preferredSize.width;
int h = preferredSize.height;
pane.setSize(w, h);
pane.addNotify();
pane.validate();
// would be nice to use this box view instead of instantiating a UI
// however, unless you call setParent() on the view it's useless
// What should the parent of a root element be?
//BoxView view = (BoxView) pane.getEditorKit().getViewFactory().create(pane.getStyledDocument().getDefaultRootElement());
//view.paint(d, new Rectangle(w, h));
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
final Graphics2D d = img.createGraphics();
d.setClip(0, 0, w, h); // throws a NullPointerException if I leave this out
pane.getUI().paint(d, pane);
d.dispose();
JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(img)));
}
Check out the ScreenImage class which allows you to create a BufferedImage of any Swing component. It should also work for Swing components that are not visible, but yes you do have to do the rendering first.