Using a Japanese font in Swing components

To answer this question, I installed a Japanese font to play around with. It’s called MS Mincho. After installing it, I modified the JDK properties so that it recognizes this font. I assume here that you are using JDK1.2.2. Go to c:\jdk1.2.2\jre\lib and copy font.properties.ja to font.properties (make a backup of the original font.properties first). Then modify this file font.properties and change serif.plain.0 to MS Mincho,ANSI_CHARSET. Also add the entry filename.MS_Mincho=msmincho.ttf.

You can use this test program that allows you to display RTF text, using the RTFEditorKit. Point the URL in the application to http://www.esus.com/docs/Hello.rtf

import javax.swing.text.html.*;
import javax.swing.text.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.*;
import java.awt.*;
import java.io.*;
 
public class Main extends JFrame
{
   public static void main(String []args) {
      Main main = new Main();
      main.show();
   }
 
   public Main() {
 
      JButton uriButton = new JButton("Go!");
      // needs to be final to allow the inner class to access it!
      final JTextField uriTextField = new JTextField();
      final JEditorPane htmlPane = new JEditorPane();
      uriTextField.setText("http://www.esus.com/docs/Hello.rtf");
      htmlPane.setEditable(false);
 
      uriButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            try {
               htmlPane.setPage(new URL(uriTextField.getText()));
            }
            catch(Exception e) {
               System.out.println(e);
            }
         }
      });
 
      getContentPane().setLayout(new BorderLayout());
      JPanel topPanel = new JPanel(new BorderLayout());
      topPanel.add(BorderLayout.CENTER, uriTextField);
      topPanel.add(BorderLayout.EAST, uriButton);
 
      getContentPane().add(BorderLayout.NORTH, topPanel);
      getContentPane().add(BorderLayout.CENTER, new JScrollPane(htmlPane));
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            System.exit(0);
         }
      });
 
      setSize(400, 400);
   }
}

Feel free to post any more sample code or detailed explanation on how to change the font.properties file to add MS Mincho properly.

Listing the available fonts on your system

You could use the Toolkit method getFontList:

      String fontnames[] = Toolkit.getDefaultToolkit().getFontList();

However, this method is deprecated. Here’s a newer version:

import java.awt.*;
 
public class Main
{
   public static void main(String[] args) {
 
     GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
     String[] fontnames = env.getAvailableFontFamilyNames();
 
     System.out.println("Available fonts:n");
     for(int i=0; i<fontnames.length; i++)
        System.out.println(fontnames[i]);
     }
}

outputs:

Available fonts:

Andale Mono IPA
Arial
Arial Black
Arial Narrow
Book Antiqua
Bookman Old Style
Century Gothic
Comic Sans MS
Courier New
Curlz MT
Default
Dialog
dialog.bold
dialog.bolditalic
dialog.italic
DialogInput
dialoginput.bold
dialoginput.bolditalic
dialoginput.italic
Edwardian Script ITC
eelfont001
eelfont002
Engravers MT
Franklin Gothic Book
Franklin Gothic Demi Cond
Franklin Gothic Heavy
Franklin Gothic Medium Cond
Garamond
Georgia Ref
Haettenschweiler
Impact
Jokerman
Juice ITC
Lucida Bright
Lucida Console
Lucida Sans
Lucida Sans Typewriter
Lucida Sans Unicode
Marlett
Mediascape OSD Icon
Mistral
Monospaced
monospaced.bold
monospaced.bolditalic
monospaced.italic
MS Reference 1
MS Reference 2
MS Reference Sans Serif
MS Reference Serif
MS Reference Specialty
OCR A Extended
RefSpecialty
Rockwell
SansSerif
sansserif.bold
sansserif.bolditalic
sansserif.italic
Serif
serif.bold
serif.bolditalic
serif.italic
Symbol
Tahoma
Tera Special
Times New Roman
Trebuchet MS
Verdana
Verdana Ref
Webdings
Wingdings
Wingdings 2

A Swing drag and drop code example

Drag and Drop is a powerful feature you should consider adding to your Java applications. When you check out the available tutorials on Java dnd, it may look fairly complex to you. Though it’s not all that hard, the hard part is remembering all the steps, objects and listeners involved. Here is a small example that shows you a basic drag and drop application (implemented with Swing).

A custom Drag and Drop (source) JList appears to the right and contains a file list of your root directory. Files with .txt extensions can be dragged upon our Drag and Drop JTextArea (target). The object transferred (Transferable) is a filename. When the drop occurs (you release the mouse button) the public void drop(DropTargetDropEvent event) is called. You can extract the filename from the Transferable object and go from there.

Main.java

import javax.swing.event.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import java.io.*;
 
public class Main extends JFrame
{
   private DNDJList list;
   private DNDJTextArea textarea;
 
   public static void main(String []args) {
      Main frame = new Main();
      frame.show();
   }
 
   public Main() {
      getContentPane().setLayout(new BorderLayout());
      list = new DNDJList(new DefaultListModel());
      getContentPane().add(BorderLayout.EAST, new JScrollPane(list));
      textarea = new DNDJTextArea();
      getContentPane().add(BorderLayout.CENTER, new JScrollPane(textarea));
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            System.exit(0);
         }
      });
 
      fillUpList(&quot;c:\&quot;);
 
      setSize(700, 300);
   }

   /**
    *  Fills up the JList with the entries in the specified directory
    */
   private void fillUpList(String directory) {
      File dir = new File(directory);
      File []files = dir.listFiles();
 
      DefaultListModel dlm = (DefaultListModel) list.getModel();
      for (int i=0; i&lt;files.length; i++) {
         dlm.addElement(directory + files[i].getName());
      }
   }
}

Our drag and drop JTextArea: DNDJTextArea.java

import java.awt.*;
import java.awt.dnd.*;
import java.awt.datatransfer.*;

import java.io.*;
import java.io.IOException;
 
import javax.swing.JTextArea;
 
public class DNDJTextArea extends JTextArea implements DropTargetListener
{
   DropTarget dropTarget = null;
  
   public DNDJTextArea() {
      // create a drop target
      dropTarget = new DropTarget(this, this);
   }
 
   public void dragEnter(DropTargetDragEvent event) { 
      event.acceptDrag(DnDConstants.ACTION_MOVE);
   }
 
   public void drop (DropTargetDropEvent event) {
      try {
         // get the object that is being transferred
         Transferable transferable = event.getTransferable();
       
         // DNDJTextArea accepts only Strings
         if (transferable.isDataFlavorSupported(DataFlavor.stringFlavor)) {
            event.acceptDrop(DnDConstants.ACTION_MOVE);
 
            String filename = (String) transferable.getTransferData(DataFlavor.stringFlavor);
            setText(readFile(filename));

            event.getDropTargetContext().dropComplete(true);
         } 
         else {
            event.rejectDrop();
         }
      }
      catch (UnsupportedFlavorException e) {
         setText(&quot;&quot;+e);
         event.rejectDrop();
      }
      catch (Exception e) {
         setText(&quot;&quot;+e);
         event.rejectDrop();
      } 
   }
 
   public void dragExit (DropTargetEvent event) { }
   public void dragOver (DropTargetDragEvent event) { }
   public void dropActionChanged (DropTargetDragEvent event) { }
 
   public String readFile(String filename) throws Exception {
      String LINEEND = System.getProperties().getProperty(&quot;line.separator&quot;);      
      StringBuffer sb = new StringBuffer();
      BufferedReader br = new BufferedReader(new FileReader(filename));
 
      String line;
      while ((line = br.readLine()) != null) {
         sb.append(line + LINEEND);
      }         
 
      return sb.toString();
   }
}

A drag and drop JList:DNDJList.java

import java.awt.dnd.*;
import java.awt.datatransfer.*;
import java.io.IOException;
import java.io.*;
 
import javax.swing.*;
 
public class DNDJList extends JList implements DragSourceListener, DragGestureListener    
{
   DragSource dragSource = null;
 
   public DNDJList(ListModel lm) {
      super(lm);
 
      // create a dragsource
      dragSource = new DragSource();
 
      // create a drag gesture recognizer
      dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this);
   }    
 
   public void dragGestureRecognized( DragGestureEvent event) {  
      String fileSelected = (String) getSelectedValue();
 
      if (fileSelected != null) {
         if (fileSelected.endsWith(&quot;.txt&quot;)) {
            // StringSelection implements Transferable, wraps the data into a transferable object
            StringSelection text = new StringSelection(fileSelected.toString()); 
        
            // start the dragging
            dragSource.startDrag(event, DragSource.DefaultMoveDrop, text, this);
         }
         else {
            SwingUtilities.invokeLater(new Runnable() {
               public void run() {
                  JOptionPane.showMessageDialog(SwingUtilities.getRootPane(DNDJList.this), 
                                                &quot;Only .txt files can be dragged!&quot;, &quot;Error&quot;,
                                                JOptionPane.ERROR_MESSAGE);
               } 
            });
         }
      } else {
         System.out.println( &quot;nothing was selected&quot;);   
      }
   }
 
   public void dragDropEnd (DragSourceDropEvent event) { }
   public void dragEnter (DragSourceDragEvent event) { }
   public void dragExit (DragSourceEvent event) { }
   public void dragOver (DragSourceDragEvent event) { }
   public void dropActionChanged ( DragSourceDragEvent event) { }
}

Getting the HWND handle of a Canvas

Sometimes, you need the HWND handle for example to pass it on with JNI to a native function. See related links, where the mousewheel support is implemented using this method.
This example shows you how to get the handle of a window as well as a Canvas.

HwndCanvas.java:

import java.awt.*;
import sun.awt.*;
 
public class HwndCanvas extends Canvas
{
   public int getHwnd() {
      int hwnd = 0;
                            
      DrawingSurfaceInfo w = ((DrawingSurface)(getPeer())).getDrawingSurfaceInfo();
                               
      if (w != null) {
         w.lock();
         Win32DrawingSurface win32 = (Win32DrawingSurface) w.getSurface();
         hwnd = win32.getHWnd();
         w.unlock();
      }
       
      return hwnd;
   }                    
}

Main.java:

import java.awt.event.*;
import java.awt.*;
import sun.awt.*;
 
public class Main extends Frame
{
   public HwndCanvas hwndCanvas = new HwndCanvas();
 
   public Main() {
      setLayout(new BorderLayout());
      add(BorderLayout.CENTER, hwndCanvas);
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            System.exit(0);
         }
      });      
 
      setSize(100, 100);
   }
 
   public int getHwnd() { 
      int hwnd = 0;
                            
      DrawingSurfaceInfo w = ((DrawingSurface)(getPeer())).getDrawingSurfaceInfo();
                               
      if (w != null) {
         w.lock();
         Win32DrawingSurface win32 = (Win32DrawingSurface) w.getSurface();
         hwnd = win32.getHWnd();
         w.unlock();
      }
      
      return hwnd;
   } 
 
   public static void main(String []args) {
      Main m = new Main();
 
      m.show();
 
      System.out.println("HWND of Frame = " + m.getHwnd());
      System.out.println("HWND of Canvas = " + m.hwndCanvas.getHwnd());
   }
}

Getting the Component with the current focus in Swing

There is a method in Window named getFocusOwner which returns the currently focused child of the window on which you invoke the method. Given that and the Frame.getFrames() method which returns all the frames created by the application, all you have to do is iterate over all the frames and find the focused component like this:

public static Component findFocusedComponent(){
  Frame [] allFrames = Frame.getFrames();
  for (int i=0;i<allFrames.length;i++){
    Frame frame = allFrames[i];
    Component focusOwner = frame.getFocusOwner();
    if (focusOwner!=null)
      return focusOwner;
  }
  return null; // if no focused component exists
}

Playing sound in a Swing application

Try out this small application with evil_laugh.wav:

import java.awt.image.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.*;
import java.awt.*;
import java.net.*;
 
public class Main extends JFrame
{
   public Main() {
      getContentPane().setLayout(new BorderLayout());
      final JLabel label = new JLabel("Sound file: ");
      final JTextField textfield = new JTextField(30);
      final JButton button = new JButton("Play");
      getContentPane().add(BorderLayout.WEST, label);
      getContentPane().add(BorderLayout.CENTER, textfield);
      getContentPane().add(BorderLayout.EAST, button);
 
      button.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            try {
               URL codebase = new URL("file:" + System.getProperty("user.dir") + "/");
               AudioClip audioClip = Applet.newAudioClip(new URL(codebase, textfield.getText()));
               audioClip.play();
            } catch (MalformedURLException e) {
               System.err.println(e.getMessage());
            }
         }
      });
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      });      
 
      pack();
   }
 
   public static void main(String []args) throws Exception {
      Main main = new Main();
      main.show();      
   }
}

Showing a JFrame without taking away the focus from the current window

You will have to use JNI. The following is an example on how to do this. The JFrame contains one button. If you click it, it will be iconified for 2 seconds and restored again, but without taking away the focus from the window that currently has the focus.

I used JDK1.3.1 and cygwin to create the DLL.

1. Main.java:

import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import java.util.*; 
 
import sun.awt.windows.*;
import sun.awt.*;
 
public class Main extends JFrame implements ActionListener
{
   public static native void WindowsShowNoActivate(int hwnd);
 
   static {
      System.loadLibrary("windowNoActivate");
   }
 
   public Main()
   {
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      });
 
      JButton iconButton = new JButton("Iconify this Frame");
      getContentPane().setLayout(new FlowLayout(FlowLayout.LEFT));
      getContentPane().add(iconButton);
      iconButton.addActionListener(this);
   }
 
   public void actionPerformed(ActionEvent ae) {     
      this.setState(Frame.ICONIFIED);  
      try {
         Thread.sleep(2000);
      }
      catch(Exception e) { }
 
      showWindowNoActivate();
      //this.setState(Frame.NORMAL);  
      //this.toBack();
   }
 
   public int getHwnd() {
      DrawingSurfaceInfo w = (DrawingSurfaceInfo) 
        ((DrawingSurface) getPeer()).getDrawingSurfaceInfo();
      w.lock();
      WDrawingSurfaceInfo win32 = (WDrawingSurfaceInfo) w;
      int hwnd = win32.getHWnd();
      w.unlock();
     
      return hwnd;
   }
 
   public void showWindowNoActivate() {
     WindowsShowNoActivate(this.getHwnd());
   }
 
   public static void main(String args[])
   {
      Main main = new Main();
      main.setSize(300, 150);
      main.setVisible(true);
   }
}

2. Compile and run javah:

c:\> javac Main.java
c:\> javah Main

3. Create windowNoActivate.c:

#include "jni.h"
#include "Main.h"
#include <stdio.h>
#include <windows.h>

JNIEXPORT void JNICALL Java_Main_WindowsShowNoActivate(JNIEnv *env, jclass obj,
jint hwnd)
{
   SetWindowPos((HWND) hwnd, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE);
   ShowWindow((HWND) hwnd, SW_SHOWNOACTIVATE);
}

4. I used Cygwin to create the DLL. There is a change that needs to be made to JDK/include/win32/jni_md.h. Add the following line:

typedef long long __int64;

5. Compile windowNoActivate.c:

$ gcc -L -DDBG -shared windowNoActivate.c -mno-cygwin 
      -I/usr/include -Ic:/jdk1.3.1/include 
      -Ic:/jdk1.3.1/include/win32 -Wl,--add-stdcall-alias -o windowNoActivate.dll

6. Put the DLL in the same directory as where your run Main from or in your path, and run it.