Some words in Arabic appear calligraphic in Swing - java

It seems that Swing auto decorate some Arabic words by making them look some kind calligraphic. One of those words is Muhammad which is spelled in Arabic as محمد.
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class TestProject extends JFrame {
public static void main(String[] args) {
TestProject frame = new TestProject();
frame.setVisible(true);
}
public TestProject() {
this.setSize(200, 100);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("محمد");
label.setFont(new Font("Arial", Font.BOLD, 28));
this.add(label);
}
}
The problem is applied to all widely used Fonts at least.
I'm using Windows 10 & Java 8. I've tried the same program on another PC (also Windows 10) same problem.
How can we disable that?

This seems to be a bug in the old (i.e. up to Java 8) font rendering engine.
This is how it looks with Java 8 on my machine:
And this is the result with Java 9:
I don’t know whether an explicit bug report has been reported for this specific issue. But the font engine has been replaced entirely, due to JEP 258: HarfBuzz Font-Layout Engine.
Replace the existing ICU OpenType font-layout engine with HarfBuzz.
So it’s not surprising that bugs of the old font rendering are gone.

(Caveat: I am not literate in Arabic.)
Appears to be font related
By default, I do not get your longer representation (3 words?) as seen in your screenshot.
When I write a minimal Swing app with the text "محمد" I get that short string (4 characters?) that you want.
When using specific fonts, I do get what looks to my untrained eye to be the calligraphic rendering you seek to avoid.
Note that my string was not your string. I copied from Google Translate, translating Muhammad as indicated in your Question.
https://translate.google.com/?sl=en&tl=ar&text=Muhammad%0A&op=translate
I wrote this minimal Swing app with just a JLabel, enhanced only by increasing font size.
package work.basil.example;
import javax.swing.*;
import java.awt.*;
/**
* Hello world!
*/
public class App {
public static void main ( String[] args ) {
System.out.println( Runtime.version() );
javax.swing.SwingUtilities.invokeLater( () -> createAndShowGUI() );
}
private static void createAndShowGUI () {
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated( true );
//Create and set up the window.
JFrame frame = new JFrame( "Test Arabic rendering" );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
//Add the ubiquitous "Hello World" label.
JLabel label = new JLabel( "محمد" );
label.setFont( new Font( label.getFont().getName() , label.getFont().getStyle() , 40 ) ); // Override default font size.
System.out.println( "Font name: " + label.getFont().getName() + " | " + "Font style: " + label.getFont().getStyle() );
frame.getContentPane().add( label );
//Display the window.
frame.pack();
frame.setVisible( true );
}
}
When run on my MacBook Pro (13-inch, M1, 2020), Apple Silicon (not Intel), 16 gigs of memory. The OS is macOS Big Sur, 11.5.1. Using early-access version of Java 17 (17+35-2724) from this page.
(By the way, this is the kind of MCVE you should have posted with your Question.)
The result of my font query is:
Font name: Lucida Grande | Font style: 0
… but I suspect that is the default font of the JLabel widget rather than the actual font used in rendering those Arabic characters. As I vaguely recall, recent versions of macOS are rich with a variety of fonts specifically for Arabic. See: Fonts included with macOS Big Sur for three lists: fonts included, fonts available for download, and older fonts available for document support. Using the Font Book app bundled with macOS, and defining a "smart collection" where languages include Arabic, I get a list of 32 such fonts installed by default in macOS Big Sur. (The four items for Pragmata Pro do not apply — that is a commercial font which I purchased, and which I highly recommend for developers.)
I ran this modified version of the code from Answer by Andrew Thompson on the same macOS Big Sur described above.
package work.basil.text;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import java.awt.*;
public class TestProject extends JFrame {
public static void main ( String[] args ) {
TestProject frame = new TestProject();
frame.setVisible( true );
}
public TestProject () {
this.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
this.setLayout( new FlowLayout() );
String input = "محمد";
String[] fontFamilies = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
for ( String fontFamily : fontFamilies ) {
Font font = new Font( fontFamily , Font.PLAIN , 40 );
if ( font.canDisplayUpTo( input ) < 0 ) {
JLabel label = new JLabel( input );
label.setFont( font );
label.setBorder( new TitledBorder( fontFamily ) );
this.add( label );
}
}
this.pack();
}
}
Here is a screenshot of the result.

Try running the code below. It produced this image on my range of installed fonts.
Note also that Arial (a sans-serif or undecorated font) seems to default to Times New Roman (a serif or decorated font) for its Arabic glyphs. This is a common thing for fonts (or systems, not sure) to do, and it produces rather odd renderings when sans-serif fonts are replaced with serif fonts.
Also note this system has 255 fonts installed, but only 23 of those support Arabic characters.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class TestProject extends JFrame {
public static void main(String[] args) {
TestProject frame = new TestProject();
frame.setVisible(true);
}
public TestProject() {
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel p = new JPanel(new GridLayout(0, 5));
String arabic = "محمد";
String[] fontFamilies = GraphicsEnvironment.
getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
for (String fontFamily : fontFamilies) {
Font font = new Font(fontFamily, Font.PLAIN, 25);
if (font.canDisplayUpTo(arabic) < 0) {
JLabel label = new JLabel(arabic);
label.setFont(font);
label.setBorder(new TitledBorder(fontFamily));
p.add(label);
}
}
this.add(new JScrollPane(p));
this.pack();
}
}

Related

JTextPane word wrapping issue

I'm using JTextPane in an application for wiki source editing. I've added a simple spell checking functionality to it which underlines mispelled words by changing character attributes to a different style via StyledDocument.setCharacterAttributes.
There are only these two styles used: the default and the 'mispelled' one. The text editor control does word wrapping, which is the expected behavior.
My problem is that there are cases (not always, but is reproducible with a specific wiki document) this character attribute changing somehow disables the word wrapping. More specifically, I delete three lines from the middle of the document, and the next run of the spell checker, when resets the character attributes to the default style (before rerunning the spell checking), the word wrapping functionality gets disabled and it remains that way. If I undo the deletion, the word wrapping goes back to normal.
Commenting out the single line that resets the style:
editorPane.getStyledDocument().setCharacterAttributes(0, editorPane.getStyledDocument().getLength(), defaultStyle, true);
solves the issue.
EDIT 1
I've extracted the problem to a simple test case. Sorry for the long line, that example text is important to reproduce the bug (it has been randomized):
package jtextpanebug;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.WindowConstants;
import javax.swing.text.Style;
public class DemoFrame extends javax.swing.JFrame {
private final JButton btResetStyle;
private final JScrollPane scrollPane;
private final JTextPane textPane;
private final Style defaultStyle;
public DemoFrame() {
// Creating a simple form with a scrollable text pane and a button
scrollPane = new JScrollPane();
textPane = new JTextPane();
btResetStyle = new JButton();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
// The text pane's text is the scrambled version of my original test data,
// it is important because the problem depends on the pane's text
// (not every text makes it wrong)
textPane.setText("= Gernela Stuff Dogo to Wnko Obuat Oebrfe Disytung hte Iidnividal Oitpcs =\n\n== Elmyonrogit ==\n\n'''memidtaie-ngiebhro opnits''' - 2 points, \nwihhc nac eb ense ot eb mmiieadte hnigeorbs fo haec othre. \nThere si no strict | cxeat defiintoin. \nEth etipcur owebl shsow sa an example optins dna the rispa \nienbg mimedtiea iebnghsor ear ncnoetced.\n\n[[Amieg:einogrhb_pinsot.pgn]]\n\n'''enihgorb optnsi distacne''' - het avaeegr of sdntaisce \nderemitedn by het mimeidate-hieobngr tonpi ipras. \n\n'''lalw''' - a iotpntes nepgesnietrr a llwa, with toerh orwds: 2 apraelll, \nevyr sloce sraufce picsee. Heer is an xamelpe. \nIt is eualgttandri ofr eterbt zisiuaitovlan.\n\n[[Gimae:llwa.npg]]\n\n'''addtaiilon emmory reeueimtnqr of na laigorthm''' - \n(eth kepa mmeory suaeg fo teh nltpiaciapo ndirug the excteouin of eht grlaotihm) - \n(hte moeymr sueag fo hte loragitmh befoer ro ftrea eht ucxeeiont of the laogrihmt)\n\n== Het Input Pnoitset Ash to Repnrsete Ufscear Arsnoelbay Elwl ==\n\nIf tno efisciped toehrwsie yb hte cdoritnpsei of an aoglirthm, \nhetn hte eqtunrmeersi of it are heste:\n\n* Ifsrt fo all the poisentt umst reprseent urfseac, not urvec ro uvomel or nayithng eesl.\n* Awlls aym otn eb tniehnr tanh at least 3 * fo ienhbgro-tpoin-sidenact.\n* Dseeg amy ton be rhserap tnha 70 grdesee (as het agnle fo eht trmeaial) nda husdol be ta tleas 290 redeseg (ni caes fo cnvocae eedgs).\n* Onpti edintsy amy ont vayr oto humc \n** Het angre fo the coall ption desitnsei of a igsenl pisnotte nutip ushold eb sallm. Ahtt is: teh orait of het oclla oitnp idsentise oarund any 2 ipnost lsdhou eb lmitied.\n** Hte lcoal noipt deisynt ushlod otn ahencg sdduelyn (gliftyscaiinn ni a hotsr idnsteac). \n\nYreftntunaoul the largoimths cna tno yb ethmsevesl \nhcekc these qutenmeserir nda usjt yden rnuning, \nso it si eth rseu's iyponerissbtil to ton extucee an raltghomi no a itseopnt \nthat does ont mete het aogitmlhr's terieseurmnq.\n\nIf eth rmeteriuqen fo na airlgmoth on its npuit is ont mte, then tobh hte ueavbhior nad hte srluet fo hte alghoritms si dinfeuned. \nTeh loirgamth amy nru rfo iinfntie long imet or rodpuce evry abd rselut, ro a eruslt htat oolsk good btu is nicrtroec. Ni htis scea rtehe si tno nay aguntreee toabu the tmniatreion of the iralgtmho ro eht lqutaiy fo the sreltu ecxept htat the nptapalcioi iwll ont carsh.\n");
scrollPane.setViewportView(textPane);
getContentPane().add(scrollPane);
btResetStyle.setText("Reset style");
btResetStyle.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
btResetStyleActionPerformed(evt);
}
});
getContentPane().add(btResetStyle);
pack();
// The default style, the problem happens when we reset the full document
// to it:
defaultStyle = textPane.addStyle("default", null);
}
private void btResetStyleActionPerformed(java.awt.event.ActionEvent evt) {
// When the button is pressed we reset the full document to the default
// style. In the original application this was periodically done as
// part of the spell checking
textPane.getStyledDocument().setCharacterAttributes(0, textPane.getStyledDocument().getLength(), defaultStyle, true);
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new DemoFrame().setVisible(true);
}
});
}
}
Reproducing the issue:
Compile and run the class above
Try to resize the frame - word wrapping works
Locate and delete the three lines I copied below
Press the Reset style button
The word wrapping turned off
* Onpti edintsy amy ont vayr oto humc
** Het angre fo the coall ption desitnsei of a igsenl pisnotte nutip ushold eb sallm. Ahtt is: teh orait of het oclla oitnp idsentise oarund any 2 ipnost lsdhou eb lmitied.
** Hte lcoal noipt deisynt ushlod otn ahencg sdduelyn (gliftyscaiinn ni a hotsr idnsteac).
EDIT 2
Using the highlighter instead of styles solved my problem, but I'm still curious what was wrong with the original approach.
This looks like the same issue I asked about here : Strange text wrapping with styled text in JTextPane with Java 7.
As far as I know, this is a bug in Java 7, and it is not documented in Oracle's Java Bug Parade. I have still not found a workaround (using the highlighter is not an option in my case).

GXT - Truncated text in a Window

I've a Window which contains two ContentPanel (horizontally), one with a Image into it and the other one with some text. The problem is that my text is truncated : it's going out of the Window...
Window win = new Window();
win.setLayout( new FillLayout() );
win.setMinWidth( 250 );
win.setHeight( 120 );
ContentPanel content = new ContentPanel( new RowLayout( Orientation.HORIZONTAL ) );
ContentPanel iconePanel = new ContentPanel( new FillLayout() );
iconePanel.add(myImage);
content.add( iconePanel, new RowData( 48, 1 ) );
Text textPanel = new Text();
textPanel.setText( msg );
content.add( textPanel, new RowData( -1, 1 ) );
win.add( content );
win.show();
How can I keep the text in the panel?
Its necessary that you should have a good understanding of different panels in the GXT,There is another trick by adjusting the padding size,Its better you use a firebug and adjust the Layout using Firebug,it will help a lot for adjusting the window.

How to make transparent JLayeredPane() and JPanel()? It always shows background of super window

How can i completely make this grey panel as transparent, so that i can see only the button "Test" but not the grey box (JPanel or JLayeredPane)
Screen shot:
public class win extends JWindow
{
...
public win()
{
super(new JFrame());
layers = new JLayeredPane();
button = new JButton("close");
this.setLayout (new BorderLayout ());
..
button.setBackground(Color.RED);
button.setSize(200,200);
button.setLocation(0,20);
this.add("North", button);
JPanel p = new JPanel();
p.setOpaque(false);
p.setSize(300, 200);
p.setLocation(0, 0);
p.add(new JButton("Test"));
layers.add(p, new Integer(1));
layers.setSize(400,300);
layers.setLocation(400,50);
layers.setOpaque(false);
this.add("North", layers);
canvas.setSize(screenSize.width,screenSize.height);
this.add("North",canvas);
//com.sun.awt.AWTUtilities.setWindowOpacity(this, 0.5f); // gives error in my Java version
}
}
Follow up: installed as recommended, but no luck yet.
ERROR not solved: Exception in thread "main" java.lang.UnsupportedOperationException: The TRANSLUCENT translucency kind is not supported.
Installed:
compiz-gnome.i686 0:0.9.4-2.fc15
Dependency Installed:
compiz-gtk.i686 0:0.9.4-2.fc15 compiz-plugins-main.i686 0:0.9.4-1.fc15
libcompizconfig.i686 0:0.9.4-1.fc15 protobuf.i686 0:2.3.0-7.fc15
Complete!
You have mail in /var/spool/mail/root
[root#example ~]# xdpyinfo | grep -i render
RENDER
You have mail in /var/spool/mail/root
[root#example ~]# xdpyinfo | grep -i comp
Composite
XVideo-MotionCompensation
[root#example ~]#
See this article or this article. Note that not all environments support all the features (translucency, per pixel transparencyt etc.) described in the article.
EDIT: On my system (Ubuntu 10.04.2 LTS, Sun java 1.6.0_26) the following code:
System.out.println("TRANSLUCENT supported: " + AWTUtilities.isTranslucencySupported(AWTUtilities.Translucency.TRANSLUCENT));
System.out.println("PERPIXEL_TRANSPARENT supported: " + AWTUtilities.isTranslucencySupported(AWTUtilities.Translucency.PERPIXEL_TRANSPARENT));
System.out.println("PERPIXEL_TRANSLUCENT supported: " + AWTUtilities.isTranslucencySupported(AWTUtilities.Translucency.PERPIXEL_TRANSLUCENT));
gives:
TRANSLUCENT supported: false
PERPIXEL_TRANSPARENT supported: true
PERPIXEL_TRANSLUCENT supported: true
EDIT2: Inspired by this discussion, I just installed and configured compiz and now the 'constant opacity level' slider of the web start application at the second article linked above suddenly can be moved to values smaller than 100% and the demo frame actually is translucent. Also the code snipped shown above now prints true for all three kinds of translucency/transparency. And AWTUtilities.setWindowOpacity(..) does not throw any more but produces a transparent window.

Java font family name discrepancy

On my WinXP box under JDK6, the following code:
import java.awt.Font;
import java.awt.GraphicsEnvironment;
public class TestFontFamily
{
public static void main(String[] args)
{
for( String s : GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames() )
{
Font f = Font.decode(s);
if( f != null && !s.equals(f.getFamily()) )
System.out.println(String.format("%-20s %s", s, f));
}
}
}
prints the following list:
Bauhaus 93 java.awt.Font[family=Dialog,name=Bauhaus,style=plain,size=93]
Bookshelf Symbol 7 java.awt.Font[family=Dialog,name=Bookshelf Symbol,style=plain,size=7]
Britannic Bold java.awt.Font[family=Dialog,name=Britannic,style=bold,size=12]
Harlow Solid Italic java.awt.Font[family=Dialog,name=Harlow Solid,style=italic,size=12]
Modern No. 20 java.awt.Font[family=Dialog,name=Modern No.,style=plain,size=20]
Wingdings 2 java.awt.Font[family=Wingdings,name=Wingdings,style=plain,size=2]
Wingdings 3 java.awt.Font[family=Wingdings,name=Wingdings,style=plain,size=3]
So the question is why font family name from Font#decode is different? And which one should I use?
It seems both have problems: getAvailableFontFamilyNames() includes style/size, and what I get from Font#decode may have wrong family/name.
A bonus question is then: What is a reliable way to get a list of fonts?
The following code does not work either, as some fonts' "name" differs from "family name", e.g. the family name of "Berlin Sans FB Demi Bold" is "Berlin Sans FB Demi".
for( Font f : GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts() )
{
if( f.getFamily().equals(f.getName()) )
System.out.println(f);
}
(I wonder what badge I may get for answering my own tumbleweed question.)
I found that Font.decode(s + " plain") gives me fonts with the right family names.

JOptionPane.showMessageDialog truncates JTextArea message

My Java GUI application needs to quickly show some text to the end-user, so the JOptionPane utility methods seem like a good fit. Moreover, the text must be selectable (for copy-and-paste) and it could be somewhat long (~100 words) so it must fit nicely into the window (no text off screen); ideally it should all be displayed at once so the user can read it without needing to interact, so scrollbars are undesirable.
I thought putting the text into a JTextArea and using that for the message in JOptionPane.showMessageDialog would be easy but it appears to truncate the text!
public static void main(String[] args) {
JTextArea textArea = new JTextArea();
textArea.setText(getText()); // A string of ~100 words "Lorem ipsum...\nFin."
textArea.setColumns(50);
textArea.setOpaque(false);
textArea.setEditable(false);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
JOptionPane.showMessageDialog(null, textArea, "Truncated!", JOptionPane.WARNING_MESSAGE);
}
How can I get the text to fit entirely into the option pane without scrollbars and selectable for copy/paste?
import java.awt.*;
import javax.swing.*;
public class TextAreaPreferredHeight2
{
public static void main(String[] args)
{
String text = "one two three four five six seven eight nine ten ";
JTextArea textArea = new JTextArea(text);
textArea.setColumns(30);
textArea.setLineWrap( true );
textArea.setWrapStyleWord( true );
textArea.append(text);
textArea.append(text);
textArea.append(text);
textArea.append(text);
textArea.append(text);
textArea.setSize(textArea.getPreferredSize().width, 1);
JOptionPane.showMessageDialog(
null, textArea, "Not Truncated!", JOptionPane.WARNING_MESSAGE);
}
}
If you need to display a string of an unknown length, you can set number of rows "on the fly":
public static void showMessageDialogFormatted(String msg, String title, int messageType, int columnWidth) {
JTextArea textArea = new JTextArea(msg);
textArea.setColumns(columnWidth);
textArea.setRows(msg.length() / columnWidth + 1);
textArea.setLineWrap(true);
textArea.setEditable(false);
textArea.setWrapStyleWord(true);
JOptionPane.showMessageDialog(null, textArea, title, messageType);
}
You've got the right idea. Just adjust the rows of your textarea.
textArea.setRows(10); // or value that seems acceptable to you...
This seemed to fix the issue for me, using 100 words of lorem ipsum.
Try this:
JTextArea textArea = new JTextArea();
textArea.setText(getText());
textArea.setSize(limit, Short.MAX_VALUE); // limit = width in pixels, e.g. 500
textArea.setWrapStyleWord(true);
textArea.setLineWrap(true);

Categories