How to show all the content of Jtable in netbeans - java

Using netbeans I was able to show the content of my database using Jtable, but the problem is that when I run the file I got the Jtable but not all of the content of the indivdual record appear entirely. Because some columns has a paragraph entry not a few words

You'd have to be able to know the number of lines & the text height used by the jtable. From there you can set the row height (globally for the table, or for individual rows).
You would then need a table cell renderer capable of displaying multi line content.
Depending on your requirements, you'd might be better of displaying a one line summary of the cell & allow for tooltips to display the full content (depending on the size of te content) or a popup window with a none editable text component
UPDATE
Sorry for the short comment, I was on my IPad.
You have two choices, depending on what state your UI is in. You can grab a reference to the FontMatrics from the JTables graphics context. This will only work if the JTable has been realised (rendered on the screen)
FontMetrics fm = myTable.getFontMetrcis(myTable.getFont());
int height = fm.getHeight();
This example, of course, assumes you are using the same font as the JTable. If not, you'll need to supply the correct font.
Or, if the UI hasn't been realised yet, you'll need to construct a compatible image a extract the font metrics from it. This is a little more complicated as it begins to deal with the graphics configuration and devices...
BufferedImage img = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().createCompatibleImage(1, 1, Transparency.TRANSLUCENT);
Graphics2D g2d = img.createGraphics();
FontMetrics fm = g2d.getFontMetrics(font);
int height = fm.getHeight();
g2d.dispose();
Once you have the height of the font, you should be able to calculate the height of the text, assuming the text is broken up into lines (or you can split the lines your self). Now if that's not the case (or you want to provide you own word/line wrapping), this become increasingly complicated.
You can check here http://docs.oracle.com/javase/tutorial/2d/text/drawmulstring.html for how to render text using graphics2D for hints (you can use this to split text into groups as you need)
You might also want to check out http://www.jroller.com/santhosh/entry/multiline_in_table_cell_editing1 which shows a great idea for a multi line editor.

Related

Issue with TextArea height

I had posted the same question in oracle javafx forum too but haven't got a response. So trying my luck here.
I have a requirement where in the content of the text area is dynamically populated from the database. I am able to successfully retrieve and display the data on the text area.
However when the content is too large, I am not able to dynamically set the height of the text area. When I try to display the same as a label, the display is flawless, dynamically sets the height as per the content. So, I tried to create a label, with same content and dynamically bind the height to the preferred height as below, but it doesn't work.
// Generate User Note Description
TextArea textArea = new TextArea();
Label text = new Label();
// SETTING THE TEXT TO A LABEL TO RETRIEVE THE HEIGHT
text.setText(usrNotes.getNote().trim());
// ALWAYS DISPLAYS 0.0
System.out.println("height::"+text.getHeight());
if (isMyNote) {
// ALWAYS SETS TO THE MINIMUM HEIGHT OF 60.0
textArea.setText(usrNotes.getNote().trim());
textArea.setPrefWidth(Screen.getPrimary().getVisualBounds().getWidth() - 500.0);
textArea.setWrapText(true);
textArea.setMinHeight(60.0);
// WITHOUT THIS BINDING, DISPLAYS LOT OF EXTRA SPACE AFTER THE TEXT
textArea.prefHeightProperty().bind(text.heightProperty());
textArea.setStyle("-fx-padding:0 5 2 1; -fx-font-size: 1.1em;-fx-background-color:white");
} else if (!isMyNote) {
// THIS IS PERFECT, AS EXPECTED SETS THE HEIGHT DYNAMICALLY
text.setText(usrNotes.getNote().trim());
text.setStyle("-fx-padding:0 5 2 1;");
text.setStyle("-fx-border-color: white;-fx-font-size: 1.1em;-fx-background-color:#F5F5F5;");
text.setWrapText(true);
text.setPrefWidth(Screen.getPrimary().getVisualBounds().getWidth() - 500.0);
text.setMinHeight(60.0);
}
I would highly appreciate if someone can provide a hint on how to resolve this issue.
Thanks -SV
The reason text.getHeight() returns 0, (and therefore have to bind to text.heightProperty()) is because the height isn't calculated when the component is constructed. It is calculated when the component is rendered to the screen.
If you want to calculate a height ahead of time, I believe you will have to use something like FontMetrics (http://docs.oracle.com/javase/tutorial/2d/text/measuringtext.html) to calculate the width and line height of your string, break up the string into tokens to figure out where line breaks will fall (based on your width), and then figure out how many lines you will need (and therefore, how high your TextArea needs to be).

Differences between Swing and iText font rendering

I'm building an app which among other things allows the user to insert a text into a PDF, using a layer.
The position of the text in the PDF page can be set using the app, which renders the PDF using ICEPdf inside a JPanel. After selecting the position and the size of the layer, the app renders it to the PDF using iText (v. 5.3.2).
The problem I'm facing is that the font rendering from Swing is sightly different from the final result in the PDF.
Here are some screen-shots, both using the Helvetica plain font inside the same bounding box:
Rendering a text with Swing:
protected void paintComponent(Graphics g){
//for each line...
g.drawString(text, b0, b1);
//b0 and b1 are computed from the selected bounding box for the text
}
I have this:
Rendering a text with iText:
PdfTemplate t; //PdfTemplate is created elsewhere
ColumnText ct = new ColumnText(t);
ct.setRunDirection(PdfWriter.RUN_DIRECTION_NO_BIDI);
ct.setSpaceCharRatio(1);
ct.setSimpleColumn(new Phrase(text, font), b0, b1, b3, b4, font.getSize(), Element.ALIGN_BOTTOM);
//b0, b1, b2 and b3 are the bounding box of the text
ct.go();
I have this:
So the question is: what can be done to make Swing and iText render fonts exactly the same way? I can tweak Swing or iText, so no matter what code is modified, I need a truly WYSIWYG experience for the user.
I tried with other fonts and types, but still there are some differences between them. I think I'm missing some configuration.
Thanks.
Edit:
Font in Java is measured in Pixels, but iText measures in Points, and we know there are 72 points per inch, and for a standard windows machine there are 96 pixels per inch / dpi.
First we need to find the difference between a point and a pixel:
difference = 72 / dpi
0.75 = 72 / 96
Next we can multiply the Java font size with the difference to get the iText font size, if the java font size is 16, then the iText font size should be 12 when used with 96dpi.
iTextFontSize = difference x javaFontSize
12 = 0.75 x 16
On a windows machine 96dpi is often the norm, but remember that is not always the case, you should work it out for each different machine.
Original Post
I believe the difference is caused by rendering hints.
Solution 1:
The best way to do it would be to draw everything on a buffered image. Then the buffered image is drawn to the swing component and the exact same buffered image is drawn to the PDF as well, that way there should be no difference between them.
Alternate Idea:
Another idea that may not work as well, but will work better with your existing code is to draw the contents of the swing component directly to a buffered image then draw the buffered image to the PDF.
The following is a quick example that will draw the contents of a JPanel to a buffered image with a few different rendering hints. (Change the hints to suit your swing component)
public BufferedImage createImage(JPanel panel)
{
BufferedImage swingComponent = new BufferedImage(
panel.getHeight(), panel.getWidth(),
BufferedImage.TYPE_INT_RGB);
Graphics2D g = swingComponent.createGraphics();
g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.dispose();
return swingComponent; //print this to your PDF
}
So the question is: what can be done to make Swing and iText render fonts exactly the same way?
Exactly the same? Very little. Presuming that you supply the same font characteristics to both, there may still be differences introduced in rendering.
PDF files (or really, the text phrases) hold font information—family, size, style, etc.—but it is your PDF reader that renders the text to your device. Depending on what program you use, it can use the platform's renderer or it can choose one of its own.
AFAIK, Java Swing uses its own font rendering engine, as distinct from the underlying platform's renderer. This makes it look more consistent across platforms, but also makes it very unlikely that text will be rendered the same way any other program would.
Knowing that, your options are limited:
Use a PDF reader that also uses Swing font rendering. That's a fairly limiting solution.
Use your platform's rendering engine to draw into Swing. That sounds like iffy work, and also like something SWT would have solved. Maybe you could embed an SWT component?

find out if text of JLabel exceeds label size

In Java when the text of the JLabel could not be displayed due to lack of space the text is truncated and "..." is added in the end.
How can I easily find out if currently JLabel displays full text or the truncated?
EDIT:
I see that there is a way to find out the size of the text by using FontMetrics. However this solution doesn't fully answers the question. In the case the text of JLabel contains HTML decorations the metrics.stringWidth() would also calculate width of HTML tags. So it could happen that result of metrics.stringWidth() would be grater than JLabel's width but still the text would be displayed correctly.
Is there a way know what decision took the JLabel itself while displaying the text. Has it decided to truncate the text or not.
The ellipsis is added by the label's UI delegate, typically a subclass of BasicLabelUI, as part of it's layout and preferred size calculation. The method layoutCL() may be overridden to examine the geometry, as shown on this example.
As a practical matter, I'd ignore the elision and show the full text in a tool tip.
From Oracle - Measuring Text:
// get metrics from the graphics
FontMetrics metrics = graphics.getFontMetrics(font);
// get the height of a line of text in this font and render context
int hgt = metrics.getHeight();
// get the advance of my text in this font and render context
int adv = metrics.stringWidth(text);
// calculate the size of a box to hold the text with some padding.
Dimension size = new Dimension(adv+2, hgt+2);
Compare size to the size of the JLabel.getSize();
I suppose if the component's preferred size is greater than it's actual size, then you can expect truncation. In order for this to work, of course, the component must already be realized.
Check this and see the layoutCompoundLabel() method. It returns a String representing the text of the label. You can compare it to the original to determine if it will be clipped.
Jim S.
The usual way to do this is to use a method that calculates the expected size of the text as it will be displayed in the label. If you're using a monospaced font, this is easy:
lengthOfChar * numChars
If you're not using a monospaced font, it's obviously much harder. I think there are some utilities around that will attempted to calculate this.
Once you have the size of the displayed string, you can compare to the length of the JLabel and see if the label is too small.
To get sizes of html text check this https://www.java.net/node/665691.
View view = (View) javax.swing.plaf.basic.BasicHTML.createHTMLView(label, value.toString());
int width = (int) view.getPreferredSpan(View.X_AXIS);
int height = (int) view.getPreferredSpan(View.Y_AXIS);
The only small problem is that it might have issues with non-html text. So, just use font metrics for non-html strings. The following worked perfectly for me:
if (value.toString().startsWith("<html>")) {
View view = (View) javax.swing.plaf.basic.BasicHTML.createHTMLView(label, value.toString());
width = (int) view.getPreferredSpan(View.X_AXIS);
}
else {
width = (int) label.getFontMetrics(label.getFont()).stringWidth(value.toString());
}

Resize font based on string length

From an xml file, I'm given a width, height and id. All of them can and do vary very quickly. Now, I'm asked to draw a rectangle using the width and height (an easy task), and place the id at its center. The id must not overflow out of the rectangle it's contained it.
For single-character strings, this is also easy - set the font size to the height, play a bit with the x position maybe, and it's centered. The problem is when it's multi-character strings.
So given a width and height and a string, how can you determine what font-size the string should appear in? Assume you have every bit of information you need on the rectangle you're drawing the string in.
[Edit]: I'm using the Graphics 2D class to draw everything.
Start with selecting a Font at your preferred (i.e. maximum) size.
Grab the FontRenderContext from your Graphics2D object using getFontRenderContext.
Use getStringBounds() on the Font to be rendered to get a Rectangle2D object for the specific String to be rendered. That object describes the final size of the String using that Font
Check if the size specified by that Rectangle2D is small enough.
4a. If it is small enough, you're done. Use the last Font you've checked.
4b. If it is too big, use Font.derive() to produce a smaller version of the Font and continue to use that and loop back to 3.
Don't quite have the time to give you a full working example, but here are a couple pointers that should get you going in the right direction. The graphics object you are using to draw with has a getFontMetrics() method, one of the methods on FontMetrics is stringWidth(String str) which gives you the width of a string in the current Font.
If the width is too big for your rectangle set the Font on the Graphics object to the same font just with a smaller size until it fits.
To horizontally center a string in a container (learned long ago in typing class in high school):
(rectangleWidth / 2) - (stringWidth / 2)
http://download.oracle.com/javase/1.5.0/docs/api/java/awt/FontMetrics.html
To create a Font with a smaller size, something like:
Font font = graphics.getFont();
Font smallerFont = font.derive(font.getSize() - 1);
graphics.setFont(smallerFont);
Hope this gets you going in the right direction.
I would recommend for this problem to remove as many unknowns as possible. In this case, the problem chiefly is that font characters can vary in width... well most. That's why I would use a good monospace font like courier new for the ID, that way you know what the width of each character is, you know the width of your rectangle and you know the number of characters in your string. You can simply reduce the pixel size of each character will till your string fits the available width.
Example, if the width of each character is 12px and you have 10 characters in your ID, then you need 120px to fit everything in. If you only have 80px available, it's simple math 80/10 = 8px font-size (reduce half a pixel for padding if you want.
Just my suggestion.

How to highlight part of a JLabel?

Before any one suggests HTML, I explain later why thats not an option here. I have a table that contains a column with text cells in it. I need to be able to highlight some of the text in each cell. So for example if the cell contained "cat foo dog"... I might want to highlight foo.
My current method is to use a custom TableCellRenderer that puts html into a JLabel component that gets rendered and for a time it was good. Then I noticed that when the text in the cell became too long to fit in the column width it just truncated the text without the normal "..." that happens normally in this case. Thus users didnt know there was more text they were not seeing. The other problem was that if the original text itself contained HTML, which in my case it does at times, the cell would not render correctly. I know I could just escape the html but I would still have the prevous problem.
If I use a component other than a jlabel then it makes my table's cells look strange. Does any one have any suggestions? Thanks
Well, here is a solution.
In short, you can subclass JLabel to draw the highlight manually. Override the paintComponent method to do the actual drawing and use FontMetrics to calculate where the highlighted region should be drawn.
Here is that answer in excruciating detail:
Basically, you can make a subclass of JLabel that can highlight stuff. I would do that like this; you may want to do it somewhat differently:
Add a method that tells the label which part to highlight. This could be something like this, assuming you just need one highlighted region:
public void highlightRegion(int start, int end) {
// Set some field to tell you where the highlight starts and ends...
}
If you need multiple regions, just have an ArrayList instead of a simple field. A method for dehighlighting would probably be useful too.
Now, you need to override the paintComponent method of JLabel. Here you need to do several discrete steps, which you may want to organize in different methods or something. For simplicity, I'll put it all in the paint method.
#Override
protected void paintComponent(Graphics g) {
...
First, you need to figure out the physical dimensions of the highlight, which you can do using the nice FontMetrics class. Create the FontMetrics class for the Font you're using.
FontMetrics metrics = new FontMetrics(getFont());
Now you can get all the information you need to create a rectangle that will be the highlight. You'll need the starting position, the height and the width. To get this, you'll need two substrings of the JLabel's text as follows:
String start = getText().substring(0, startOfHighlight);
String text = getText().substring(startOfHighlight, endOfHighlight);
//You may also need to account for some offsets here:
int startX = metrics.stringWidth(start);
int startY = 0; //You probably have some vertical offset to add here.
int length = metrics.stringWidth(text);
int height = metrics.getHeight();
Now you can draw the highlighted region before drawing the rest of the label:
g.fillRect(startX, startY, length, height);
super.paintComponent(g);
}
Of course, if you want the highlight to span multiple rows, that will require more work.
If you were wondering, I have actually written something like this before. On a whim, I decided to write my own text area type component from a JPanel, and this was basically the way I handled highlighting. Reinventing the wheel may be stupid in an actual project, but it does teach you random stuff that may come in useful...
Can't resist to throw the SwingX renderer decoration mechanism into the ring: its way to solve the requirement is to implement a Highlighter doing it. Which in fact is already done (though not yet in the officially supported) but hidden in the SwingLabs-Demos project, named X/MatchingTextHighlighter (you would need both) and recently fixed to cope with icons, RToL-ComponentOrientation, alignment, ellipses ..
Thats a great answer, and probably the best solution. But an alternative that some might find simpler is to use a JTextfield instead of a JLabel for rendering then you can use JTextfields highlighting capabilities i.e
void highlightWhitespaceText(JTextField text)
{
text.setHighlighter(AbstractTableCellRenderer.defaultHighlighter);
try
{
Matcher m = AbstractTableCellRenderer.whitespaceStartPattern.matcher(text.getText());
if (m.matches())
{
text.getHighlighter().addHighlight(m.start(1), m.end(1), AbstractTableCellRenderer.highlightPainter);
}
m = AbstractTableCellRenderer.whitespaceEndPattern.matcher(text.getText());
if (m.matches())
{
text.getHighlighter().addHighlight(m.start(1), m.end(1), AbstractTableCellRenderer.highlightPainter);
}
}
catch (BadLocationException ble)
{
//
}
}
You can change the properties of a JTextfield so it looks like a jLabel in other respects.

Categories

Resources