Closed iclkevin closed 3 months ago
I was curious if I could maybe find the cause of this issue, this is what I have found so far:
Since 3.5 there is a new FlatHTML
class that adds a BASE_SIZE
to the stylesheet of the HTML (line 70):
// BASE_SIZE rule is parsed in javax.swing.text.html.StyleSheet.addRule()
styleSheet.addRule( "BASE_SIZE " + fontBaseSize );
clearViewCaches( view );
When I remove this line the HTML is no longer cutoff.
I started playing around with the fontBaseSize
value that is passed and I noticed that different values result in different minimum/preferred/maximum sizes of the JLabel but the actual rendering of the JLabel stays the same. I enabled the debug printing using dumpViews
and this shows that the font size of the InlineView
's (that render all the individual pieces of html) is being updated.
I don't yet understand why the updated font size is being used for calculating the layout of the label but not being used for the actual rendering, I will try to look into this further.
I added a mouse listener to the label which calls FlatHTML.dumpViews( view, 0 )
on the label, when I click it I see that the original font sizes from before the BASE_SIZE was set are now printed (except for the very last InlineView which still shows the desired font size). I verified that these are the fonts/sizes that are used by GlyphPainter1
for painting the HTML.
I also print the preferred size of the label in the mouse listener and this always prints the same dimension (which resulted from changing the BASE_SIZE), even when revalidating/forcing doLayout etc.
I am still learning about how Swing renders it's text components, but I think I'm getting closer.
This seems to be caused by the <div style=\"width:250px;\">
, there is no closing </div>
in the provided sample bit if I add it myself the html is still cutoff.
If I remove the <div>
from the html everything works ok, the BASE_SIZE value that I was changing in my tests is now also being used.
I do not know a better way to force a particular wrap width on a JLabel without the div defined with the width attribute. I apologize about missing the closing div in the example; it should have no effect.
If the <div>
was working in previous releases then I agree this is probably a new issue in 3.5, as a workaround maybe you could use a LayoutManager like GridBagLayout, in my tests I simply changed your code to:
GridBagLayout layout = new GridBagLayout();
layout.rowWeights = new double[] { 0.1, 0.1, 0.1 };
layout.rowHeights = new int[] { 10, 250, 10 };
layout.columnWeights = new double[] { 0.1, 0.0, 0.1 };
layout.columnWidths = new int[] { 10, 250, 10 };
content.setLayout(layout);
GridBagConstraints c = new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0);
I appreciate this. Unfortunately, this workaround is a bit too cumbersome for practical use, as layouts get more complex. I am still playing around too (adding extra return lines at the end and such). Hopefully this can be resolved in FlatLaF.
I also tried setting the width in the body of the html <html><body width=\"250px\"><small>Lorem ipsum...
but this has the same issue. Yes I agree it would be nice if this html also works in combination with the BASE_SIZE fix in 3.5, or maybe a way to configure if the BASE_SIZE rule should be applied or not (because I think it might be due to a swing-bug when the html gets a little bit complex).
Personally I would try to avoid relying on the html for layout, if you want to show multiline wrapped text you could also try to use a JTextArea
or a JTextPane
, and you could also create a utility class which you can reuse for displaying a label with a fixed width, for example:
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JPanel;
public class FixedWidthPanel extends JPanel {
public FixedWidthPanel(Component c, int w) {
GridBagLayout layout = new GridBagLayout();
layout.rowWeights = new double[] { 0.1 };
layout.rowHeights = new int[] { 10 };
layout.columnWeights = new double[] { 0.0 };
layout.columnWidths = new int[] { w };
setLayout(layout);
add(c, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
}
}
You can then simply wrap your label by adding it like so:
content.add(new FixedWidthPanel(label, 250), c);
Thank you, @remcopoelstra. This discussion was very helpful. The problem here seems mainly to be caused by a mismatch in sizing from the \ tag. If this tag is removed, the full text is visible, albeit larger in size. The HTML rendering engine for Swing inherits its style sheet from the current LaF of the JComponent. So using FlatLaF's styleClass property works well with a wrapped JLabel:
public static void main(String[] args) throws UnsupportedLookAndFeelException {
UIManager.setLookAndFeel(new FlatMacLightLaf());
JFrame f = new JFrame();
JPanel content = new JPanel(new GridBagLayout());
content.setPreferredSize(new Dimension(500, 500));
GridBagConstraints c = new GridBagConstraints();
JLabel l = new JLabel("<html><div style=\"width:250px;\">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque venenatis odio quis leo cursus, a scelerisque dui consequat. Nunc vel tincidunt erat. Cras non lacinia tellus. Donec semper ante in neque ornare, non vehicula dui consequat. Cras in posuere nulla. Duis tincidunt a neque at consequat. Proin et massa augue. Phasellus tempus, felis non varius vestibulum, nisl eros sagittis lacus, vel commodo ex massa non ipsum. Aliquam eget augue odio. Cras consequat posuere pharetra. Morbi vel est ultrices, iaculis orci id, aliquet ligula. Aenean posuere tellus id augue lacinia, ac vestibulum tellus sollicitudin. Phasellus dignissim justo sit amet quam pharetra pharetra. Curabitur ut lacus dignissim, egestas sem et, ullamcorper nibh. Fusce placerat bibendum sollicitudin. Mauris eleifend urna iaculis eros bibendum, id vulputate ante posuere.</div></html>");
l.putClientProperty("FlatLaf.styleClass", "mini");
content.add(l, c);
f.setContentPane(content);
f.pack();
f.setVisible(true);
}
I am happy with this solution and I feel it makes more sense than using the tag. I don't know if the admins want to keep this issue open for the \ tag incompatibility, but I consider this a non-issue at this point.
We use small tag across our codebase and have now noticed this issue too. It would be good id LAF itself handled this correctly instead of having to avoid certain tags
Already working on this 😉
@KlemenDEV where can I see this issue in MCreator?
I have not personally replicated it yet, just heard from a dev. I will check asap and let you know
@iclkevin @remcopoelstra thanks for reporting and looking into this. 👍
This was difficult to find... Turned out that not the preferred size was too small, but the font used for painting was too large.
In FlatLaf 3.5, HTML is parsed and converted to a View hierarchy, then a BASE_SIZE rule is added to style sheet and caches of view hierarchy are cleared, which later recreates fonts using the new BASE_SIZE:
styleSheet.addRule( "BASE_SIZE " + fontBaseSize );
clearViewCaches( view );
Unfortunately, class FlowView
holds a copy of some views in field FlowView.layoutPool
and it is not possible to clear font cache in those views.
On relayout, views from FlowView.layoutPool
are cloned (in GlyphView.createFragment()
)
and new views use wrong font size. The relayout is triggered by painting the view.
The fix for 3.5.1 now inserts BASE_SIZE rule into HTML.
fixed in latest 3.5.1-SNAPSHOT
: https://github.com/JFormDesigner/FlatLaf#snapshots
I will do more testing and report back if anything is found, but I am assuming our case was fixed too
In v3.5.0 of FlatLaF, including wrapped HTML in a JLabel (and probably other components) results in the bottom line or more being cutoff. This issue does not exist in v3.4.1.
Please let me know if I can help further.