fixed/improved vertical position of text when scaled on HiDPI screens on Windows when running on Java 9 or later

This commit is contained in:
Karl Tauber
2020-06-22 13:45:56 +02:00
parent ea2412d3a7
commit 15a714faed
12 changed files with 413 additions and 17 deletions

View File

@@ -18,6 +18,8 @@ FlatLaf Change Log
`Spinner.buttonStyle` to `button` (default) or `none`). `Spinner.buttonStyle` to `button` (default) or `none`).
- TableHeader: Support top/bottom/left positioned sort arrow when using - TableHeader: Support top/bottom/left positioned sort arrow when using
[Glazed Lists](https://github.com/glazedlists/glazedlists). (issue #113) [Glazed Lists](https://github.com/glazedlists/glazedlists). (issue #113)
- Fixed/improved vertical position of text when scaled on HiDPI screens on
Windows when running on Java 9 or later.
## 0.36 ## 0.36

View File

@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JEditorPane; import javax.swing.JEditorPane;
@@ -28,6 +29,7 @@ import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicEditorPaneUI; import javax.swing.plaf.basic.BasicEditorPaneUI;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.util.HiDPIUtils;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JEditorPane}. * Provides the Flat LaF UI delegate for {@link javax.swing.JEditorPane}.
@@ -119,6 +121,11 @@ public class FlatEditorPaneUI
return size; return size;
} }
@Override
protected void paintSafely( Graphics g ) {
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
}
@Override @Override
protected void paintBackground( Graphics g ) { protected void paintBackground( Graphics g ) {
JTextComponent c = getComponent(); JTextComponent c = getComponent();

View File

@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.FontMetrics; import java.awt.FontMetrics;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import javax.swing.Icon; import javax.swing.Icon;
@@ -29,7 +30,9 @@ import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicHTML; import javax.swing.plaf.basic.BasicHTML;
import javax.swing.plaf.basic.BasicLabelUI; import javax.swing.plaf.basic.BasicLabelUI;
import javax.swing.text.View;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -124,6 +127,12 @@ public class FlatLabelUI
BasicHTML.updateRenderer( c, text ); BasicHTML.updateRenderer( c, text );
} }
@Override
public void paint( Graphics g, JComponent c ) {
View v = (View) c.getClientProperty( BasicHTML.propertyKey );
super.paint( (v != null) ? HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) : g, c );
}
@Override @Override
protected void paintEnabledText( JLabel l, Graphics g, String s, int textX, int textY ) { protected void paintEnabledText( JLabel l, Graphics g, String s, int textX, int textY ) {
int mnemIndex = FlatLaf.isShowMnemonics() ? l.getDisplayedMnemonicIndex() : -1; int mnemIndex = FlatLaf.isShowMnemonics() ? l.getDisplayedMnemonicIndex() : -1;

View File

@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit; import java.awt.Toolkit;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter; import java.awt.event.KeyAdapter;
@@ -33,6 +34,7 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicPasswordFieldUI; import javax.swing.plaf.basic.BasicPasswordFieldUI;
import javax.swing.text.Caret; import javax.swing.text.Caret;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.util.HiDPIUtils;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}. * Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}.
@@ -153,7 +155,8 @@ public class FlatPasswordFieldUI
FlatTextFieldUI.paintBackground( g, getComponent(), isIntelliJTheme ); FlatTextFieldUI.paintBackground( g, getComponent(), isIntelliJTheme );
FlatTextFieldUI.paintPlaceholder( g, getComponent(), placeholderForeground ); FlatTextFieldUI.paintPlaceholder( g, getComponent(), placeholderForeground );
paintCapsLock( g ); paintCapsLock( g );
super.paintSafely( g );
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
} }
protected void paintCapsLock( Graphics g ) { protected void paintCapsLock( Graphics g ) {

View File

@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JTextArea; import javax.swing.JTextArea;
@@ -27,6 +28,7 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTextAreaUI; import javax.swing.plaf.basic.BasicTextAreaUI;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.util.HiDPIUtils;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextArea}. * Provides the Flat LaF UI delegate for {@link javax.swing.JTextArea}.
@@ -89,6 +91,11 @@ public class FlatTextAreaUI
FlatEditorPaneUI.propertyChange( getComponent(), e ); FlatEditorPaneUI.propertyChange( getComponent(), e );
} }
@Override
protected void paintSafely( Graphics g ) {
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
}
@Override @Override
protected void paintBackground( Graphics g ) { protected void paintBackground( Graphics g ) {
JTextComponent c = getComponent(); JTextComponent c = getComponent();

View File

@@ -38,6 +38,7 @@ import javax.swing.plaf.basic.BasicTextFieldUI;
import javax.swing.text.Caret; import javax.swing.text.Caret;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.util.HiDPIUtils;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextField}. * Provides the Flat LaF UI delegate for {@link javax.swing.JTextField}.
@@ -146,7 +147,8 @@ public class FlatTextFieldUI
protected void paintSafely( Graphics g ) { protected void paintSafely( Graphics g ) {
paintBackground( g, getComponent(), isIntelliJTheme ); paintBackground( g, getComponent(), isIntelliJTheme );
paintPlaceholder( g, getComponent(), placeholderForeground ); paintPlaceholder( g, getComponent(), placeholderForeground );
super.paintSafely( g );
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
} }
@Override @Override

View File

@@ -18,6 +18,7 @@ package com.formdev.flatlaf.ui;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JEditorPane; import javax.swing.JEditorPane;
@@ -26,6 +27,7 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTextPaneUI; import javax.swing.plaf.basic.BasicTextPaneUI;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.util.HiDPIUtils;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextPane}. * Provides the Flat LaF UI delegate for {@link javax.swing.JTextPane}.
@@ -99,6 +101,11 @@ public class FlatTextPaneUI
return FlatEditorPaneUI.applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth ); return FlatEditorPaneUI.applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth );
} }
@Override
protected void paintSafely( Graphics g ) {
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
}
@Override @Override
protected void paintBackground( Graphics g ) { protected void paintBackground( Graphics g ) {
JTextComponent c = getComponent(); JTextComponent c = getComponent();

View File

@@ -29,6 +29,7 @@ import javax.swing.SwingUtilities;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicHTML; import javax.swing.plaf.basic.BasicHTML;
import javax.swing.plaf.basic.BasicToolTipUI; import javax.swing.plaf.basic.BasicToolTipUI;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
/** /**
@@ -130,7 +131,7 @@ public class FlatToolTipUI
FlatUIUtils.drawString( c, g, line, leftToRight ? x : x2 - SwingUtilities.computeStringWidth( fm, line ), y ); FlatUIUtils.drawString( c, g, line, leftToRight ? x : x2 - SwingUtilities.computeStringWidth( fm, line ), y );
} }
} else } else
super.paint( g, c ); super.paint( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ), c );
} }
private boolean isMultiLine( JComponent c ) { private boolean isMultiLine( JComponent c ) {

View File

@@ -46,7 +46,6 @@ import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.util.DerivedColor; import com.formdev.flatlaf.util.DerivedColor;
import com.formdev.flatlaf.util.Graphics2DProxy; import com.formdev.flatlaf.util.Graphics2DProxy;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.JavaCompatibility;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -449,23 +448,24 @@ public class FlatUIUtils
} }
/** /**
* Draws the given string at the specified location using text properties * Draws the given string at the specified location.
* and anti-aliasing hints from the provided component. * The provided component is used to query text properties and anti-aliasing hints.
* * <p>
* Use this method instead of Graphics.drawString() for correct anti-aliasing. * Use this method instead of {@link Graphics#drawString(String, int, int)} for correct anti-aliasing.
* * <p>
* Replacement for SwingUtilities2.drawString() * Replacement for {@code SwingUtilities2.drawString()}.
* Uses {@link HiDPIUtils#drawStringWithYCorrection(JComponent, Graphics2D, String, int, int)}.
*/ */
public static void drawString( JComponent c, Graphics g, String text, int x, int y ) { public static void drawString( JComponent c, Graphics g, String text, int x, int y ) {
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, -1, x, y ); HiDPIUtils.drawStringWithYCorrection( c, (Graphics2D) g, text, x, y );
} }
/** /**
* Draws the given string at the specified location underlining the specified * Draws the given string at the specified location underlining the specified character.
* character. The provided component is used to query text properties and * The provided component is used to query text properties and anti-aliasing hints.
* anti-aliasing hints. * <p>
* * Replacement for {@code SwingUtilities2.drawStringUnderlineCharAt()}.
* Replacement for SwingUtilities2.drawStringUnderlineCharAt() * Uses {@link HiDPIUtils#drawStringUnderlineCharAtWithYCorrection(JComponent, Graphics2D, String, int, int, int)}.
*/ */
public static void drawStringUnderlineCharAt( JComponent c, Graphics g, public static void drawStringUnderlineCharAt( JComponent c, Graphics g,
String text, int underlinedIndex, int x, int y ) String text, int underlinedIndex, int x, int y )
@@ -487,7 +487,7 @@ public class FlatUIUtils
}; };
} }
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, underlinedIndex, x, y ); HiDPIUtils.drawStringUnderlineCharAtWithYCorrection( c, (Graphics2D) g, text, underlinedIndex, x, y );
} }
public static boolean hasOpaqueBeenExplicitlySet( JComponent c ) { public static boolean hasOpaqueBeenExplicitlySet( JComponent c ) {

View File

@@ -16,9 +16,11 @@
package com.formdev.flatlaf.util; package com.formdev.flatlaf.util;
import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.text.AttributedCharacterIterator;
import javax.swing.JComponent; import javax.swing.JComponent;
/** /**
@@ -95,4 +97,116 @@ public class HiDPIUtils
private static double normalize( double value ) { private static double normalize( double value ) {
return Math.floor( value + 0.25 ) + 0.25; return Math.floor( value + 0.25 ) + 0.25;
} }
private static Boolean useTextYCorrection;
private static boolean useTextYCorrection() {
if( useTextYCorrection == null )
useTextYCorrection = Boolean.valueOf( System.getProperty( "flatlaf.useTextYCorrection", "true" ) );
return useTextYCorrection;
}
/**
* When painting text on HiDPI screens and the JRE scales, then the text is
* painted too far down on some operating systems.
* The higher the system scale factor is, the more.
* <p>
* This methods computes a correction value for the Y position.
*/
public static float computeTextYCorrection( Graphics2D g ) {
if( !useTextYCorrection() || !SystemInfo.IS_WINDOWS || !SystemInfo.IS_JAVA_9_OR_LATER )
return 0;
AffineTransform t = g.getTransform();
double scaleY = t.getScaleY();
if( scaleY < 1.25 )
return 0;
// Text is painted at slightly different Y positions depending on scale factor
// and Y position of component.
// The exact reason is not yet known (to me), but there are several factors:
// - fractional scale factors result in fractional component Y device coordinates
// - fractional text Y device coordinates are rounded for horizontal lines of characters
// - maybe different rounding methods for drawing primitives (e.g. rectangle) and text
// - Java adds 0.5 to X/Y positions in before drawing string in BufferedTextPipe.enqueueGlyphList()
// this is not the optimal solution, but works very good in most cases
// (tested with class FlatPaintingStringTest on Windows 10 with font "Segoe UI")
if( scaleY <= 1.25 )
return -0.875f;
if( scaleY <= 1.5 )
return -0.625f;
if( scaleY <= 1.75 )
return -0.875f;
if( scaleY <= 2.0 )
return -0.75f;
if( scaleY <= 2.25 )
return -0.875f;
if( scaleY <= 3.5 )
return -0.75f;
return -0.875f;
}
/**
* Applies Y correction and draws the given string at the specified location.
* The provided component is used to query text properties and anti-aliasing hints.
* <p>
* Use this method instead of {@link Graphics#drawString(String, int, int)} for correct anti-aliasing.
* <p>
* Replacement for {@code SwingUtilities2.drawString()}.
*/
public static void drawStringWithYCorrection( JComponent c, Graphics2D g, String text, int x, int y ) {
drawStringUnderlineCharAtWithYCorrection( c, g, text, -1, x, y );
}
/**
* Applies Y correction and draws the given string at the specified location underlining the specified character.
* The provided component is used to query text properties and anti-aliasing hints.
* <p>
* Replacement for {@code SwingUtilities2.drawStringUnderlineCharAt()}.
*/
public static void drawStringUnderlineCharAtWithYCorrection( JComponent c,
Graphics2D g, String text, int underlinedIndex, int x, int y )
{
float yCorrection = computeTextYCorrection( g );
if( yCorrection != 0 ) {
g.translate( 0, yCorrection );
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, underlinedIndex, x, y );
g.translate( 0, -yCorrection );
} else
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, underlinedIndex, x, y );
}
/**
* Creates a graphics object and applies Y correction to string drawing methods.
* If no Y correction is necessary, the passed in graphics object is returned.
*/
public static Graphics2D createGraphicsTextYCorrection( Graphics2D g ) {
float yCorrection = computeTextYCorrection( g );
if( yCorrection == 0 )
return g;
return new Graphics2DProxy( g ) {
@Override
public void drawString( String str, int x, int y ) {
super.drawString( str, x, y + yCorrection );
}
@Override
public void drawString( String str, float x, float y ) {
super.drawString( str, x, y + yCorrection );
}
@Override
public void drawString( AttributedCharacterIterator iterator, int x, int y ) {
super.drawString( iterator, x, y + yCorrection );
}
@Override
public void drawString( AttributedCharacterIterator iterator, float x, float y ) {
super.drawString( iterator, x, y + yCorrection );
}
};
}
} }

View File

@@ -0,0 +1,223 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.testing;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.geom.AffineTransform;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.Graphics2DProxy;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.JavaCompatibility;
import com.formdev.flatlaf.util.SystemInfo;
import net.miginfocom.swing.*;
/**
* @author Karl Tauber
*/
public class FlatPaintingStringTest
extends JPanel
{
public static void main( String[] args ) {
System.setProperty( "sun.java2d.uiScale", "1x" );
SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatPaintingStringTest" );
ToolTipManager.sharedInstance().setInitialDelay( 0 );
ToolTipManager.sharedInstance().setDismissDelay( 10000 );
frame.showFrame( FlatPaintingStringTest::new );
} );
}
FlatPaintingStringTest() {
initComponents();
if( !SystemInfo.IS_JAVA_9_OR_LATER ) {
add( new JLabel( "requires Java 9 or later" ) );
return;
}
add( new JLabel() );
add( new JLabel( "none" ) );
add( new JLabel( "flatlaf" ) );
add( new JLabel( "0.25*scale" ) );
add( new JLabel( "0.5*scale" ) );
add( new JLabel( "0.25" ) );
add( new JLabel( "0.5" ) );
add( new JLabel( "0.625" ) );
add( new JLabel( "0.75" ) );
add( new JLabel( "0.875" ) );
YCorrectionFunction none = (g, scaleFactor) -> 0;
YCorrectionFunction flatlaf = (g, scaleFactor) -> HiDPIUtils.computeTextYCorrection( g );
YCorrectionFunction oneQSysScale = (g, scaleFactor) -> -(0.25f * scaleFactor);
YCorrectionFunction halfSysScale = (g, scaleFactor) -> -(0.5f * scaleFactor);
YCorrectionFunction oneQ = (g, scaleFactor) -> -0.25f;
YCorrectionFunction half = (g, scaleFactor) -> -0.5f;
YCorrectionFunction fiveEights = (g, scaleFactor) -> -0.625f;
YCorrectionFunction threeQ = (g, scaleFactor) -> -0.75f;
YCorrectionFunction sevenEights = (g, scaleFactor) -> -0.875f;
float[] scaleFactors = new float[] { 1f, 1.25f, 1.5f, 1.75f, 2f, 2.25f, 2.5f, 3f, 3.5f, 4f };
for( float scaleFactor : scaleFactors ) {
add( new JLabel( String.valueOf( scaleFactor ) ), "newLine" );
add( scaleFactor, none );
add( scaleFactor, flatlaf );
add( scaleFactor, oneQSysScale );
add( scaleFactor, halfSysScale );
add( scaleFactor, oneQ );
add( scaleFactor, half );
add( scaleFactor, fiveEights );
add( scaleFactor, threeQ );
add( scaleFactor, sevenEights );
}
}
private void add( float scaleFactor, YCorrectionFunction correctionFunction ) {
add( new Painter( scaleFactor, correctionFunction, 0 ), "split 4, gapx 0 0" );
add( new Painter( scaleFactor, correctionFunction, 0.25f ), "gapx 0 0" );
add( new Painter( scaleFactor, correctionFunction, 0.5f ), "gapx 0 0" );
add( new Painter( scaleFactor, correctionFunction, 0.75f ), "gapx 0 0" );
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
//======== this ========
setBorder(null);
setLayout(new MigLayout(
"insets dialog,hidemode 3",
// columns
"[fill]",
// rows
"[fill]"));
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
// JFormDesigner - End of variables declaration //GEN-END:variables
private interface YCorrectionFunction {
float computeTextYCorrection( Graphics2D g, float scaleFactor );
}
//---- class Painter ------------------------------------------------------
public static class Painter
extends JLabel
{
private final float scaleFactor;
private final YCorrectionFunction correctionFunction;
private final float yOffset;
public Painter( float scaleFactor, YCorrectionFunction correctionFunction, float yOffset ) {
super( "E" );
this.scaleFactor = scaleFactor;
this.correctionFunction = correctionFunction;
this.yOffset = yOffset;
setBorder( new EmptyBorder( 2, 4, 2, 0 ) );
}
@Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
Insets insets = getInsets();
int leftRight = insets.left + insets.right;
return new Dimension(
scale( size.width -leftRight ) + leftRight,
scale( size.height ) );
}
@Override
protected void paintComponent( Graphics g ) {
Graphics2D g2 = (Graphics2D) g;
FlatUIUtils.setRenderingHints( g2 );
// simulate component y position at a fraction
if( scaleFactor > 1 )
g2.translate( 0, yOffset );
int width = getWidth();
int height = getHeight();
Insets insets = getInsets();
FontMetrics fm = getFontMetrics( getFont() );
// paint lines at 1x
HiDPIUtils.paintAtScale1x( g2, 0, 0, width, height,
(g2d, x2, y2, width2, height2, scaleFactor2) -> {
// g.setColor( Color.blue );
// g.drawLine( 0, 0, width2, 0 );
// g.drawLine( 0, height2 - 1, width2, height2 - 1 );
int baseline = (int) Math.round( (insets.top + fm.getAscent()) * scaleFactor2 * scaleFactor ) - 1;
int topline = height2 - baseline - 1;
g.setColor( Color.red );
g.drawLine( 0, baseline, width2, baseline );
g.drawLine( 0, topline, width2, topline );
} );
// move x before scaling to have same left inset at all scale factors
g.translate( insets.left, 0 );
// scale
((Graphics2D)g).scale( scaleFactor, scaleFactor );
// compute Y correction
float yCorrection = correctionFunction.computeTextYCorrection( g2, scaleFactor );
// create graphics that applies Y correction
Graphics2D cg = new Graphics2DProxy( g2 ) {
@Override
public void drawString( String str, int x, int y ) {
super.drawString( str, x, y + yCorrection );
}
@Override
public void drawString( String str, float x, float y ) {
super.drawString( str, x, y + yCorrection );
}
};
// draw string
g.setColor( getForeground() );
int y = insets.top + fm.getAscent();
JavaCompatibility.drawStringUnderlineCharAt( this, cg, "E", -1, 0, y );
// set tooltip text
if( getToolTipText() == null ) {
AffineTransform t = g2.getTransform();
double textY = t.getTranslateY() + (y * t.getScaleY());
setToolTipText( textY + " + " + yCorrection + " = " + (textY + yCorrection) );
}
}
private int scale( int value ) {
return Math.round( value * scaleFactor );
}
}
}

View File

@@ -0,0 +1,21 @@
JFDML JFormDesigner: "7.0.2.0.298" Java: "14" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
root: new FormRoot {
auxiliary() {
"JavaCodeGenerator.defaultVariableLocal": true
}
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets dialog,hidemode 3"
"$columnConstraints": "[fill]"
"$rowConstraints": "[fill]"
} ) {
name: "this"
"border": sfield com.jformdesigner.model.FormObject NULL_VALUE
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 450, 300 )
} )
}
}