[Java]102 JButtonの継承

JButtonのToolTipTextの位置を調整するため、これを継承したJButtonExクラスを作成しました。

コンストラクタも自動的に継承されるものと思っていましたが、きちんと書かないとエラーになります。

public static class JButtonEx extends JButton {
		public JButtonEx(String str) {
			setText(str);
		}
		public JButtonEx() {
		}
		@Override
		public Point getToolTipLocation(MouseEvent e) {
			Point po = e.getPoint();
			po.x += 20;
			po.y -= 10;
			return po;
		}
	}

[Java]101 UIDefaultsの内容を出力

Look and Feelの自製を見据え、UIDefaultsの内容を出力してみました。

コードはGitHubにあったものに加筆してkeyだけでなくvalueも出力できるようにしました。

以下のようになります。

import java.util.Enumeration;
import java.util.TreeSet;
import javax.swing.UIDefaults;
import javax.swing.UIManager;

public class ListUIDefaultsKeys {
	public static void main(String args[]) throws Exception {
		UIManager.LookAndFeelInfo looks[] = UIManager.getInstalledLookAndFeels();

		for (UIManager.LookAndFeelInfo info : looks) {
			System.out.println("Installed L&F "+info.getName());
		}

		TreeSet<String> lafDefaultKeys = new TreeSet<>();
		UIDefaults defaults = UIManager.getDefaults();

		Enumeration<Object> newKeys = defaults.keys();
		while (newKeys.hasMoreElements()) {
				lafDefaultKeys.add(newKeys.nextElement().toString());
		}

		System.out.println("================== UIDefaults Keys & Values ==================");
		
		int i = 1;
		for (String key : lafDefaultKeys) {
				try {
						String value = defaults.get(key).toString();
						System.out.println(String.format("%03d", i) + " " + key );
						System.out.println("    " + value);
				} catch (Exception e){
						e.printStackTrace();
				}
				i++;
		}
	}
}
--------------------------------------------------

出力の一部
--------------------------------------------------
================== UIDefaults Keys & Values ==================
001 AbstractButton.click.textAndMnemonic
    クリック
002 AbstractDocument.addition.textAndMnemonic
    追加
003 AbstractDocument.deletion.textAndMnemonic
    削除
004 AbstractDocument.redo.textAndMnemonic
    やり直し
005 AbstractDocument.styleChange.textAndMnemonic
    スタイル変更
006 AbstractDocument.undo.textAndMnemonic
    元に戻す
007 AbstractUndoableEdit.redo.textAndMnemonic
    やり直し
008 AbstractUndoableEdit.undo.textAndMnemonic
    元に戻す
009 AuditoryCues.allAuditoryCues
    [Ljava.lang.Object;@4ac68d3e
010 AuditoryCues.cueList
    [Ljava.lang.Object;@4ac68d3e
011 AuditoryCues.noAuditoryCues
    [Ljava.lang.Object;@3339ad8e
<以下略>

参考サイト

[Java]100 VSCode:Extension Pack for Javaとjavacコマンドの比較

表題の件、Javaソースコードのコンパイルエラー時に得られる情報量に雲泥の差がありました。Extension Pack for Javaは設定を変えればjavacと同レベルになるのでしょうがデフォルトがあまりにもしょぼ過ぎました。

# VSCode Extension Pack for Java
--------------------------------------------------
Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
        Unreachable catch block for InvalidPropertiesFormatException. This exception is never thrown from the try statement body
        Unreachable catch block for FileNotFoundException. This exception is never thrown from the try statement body
        Unreachable catch block for IOException. This exception is never thrown from the try statement body
        at XMLtoSetProperty.main(XMLtoSetProperty.java:32)
--------------------------------------------------

# javacコマンド
--------------------------------------------------
XMLtoSetProperty.java:32: エラー: 例外FileNotFoundExceptionは対応するtry文の本体ではスローされません
		} catch (FileNotFoundException e){
		  ^
XMLtoSetProperty.java:34: エラー: 例外IOExceptionは対応するtry文の本体ではスローされません
		} catch (IOException e){
		  ^
XMLtoSetProperty.java:36: エラー: 例外InvalidPropertiesFormatExceptionはすでに捕捉されています
		} catch (InvalidPropertiesFormatException e){
		  ^
XMLtoSetProperty.java:58: エラー: 例外IOExceptionは報告されません。スローするには、捕捉または宣言する必要があります
				in.close();
				        ^
XMLtoSetProperty.java:54: エラー: 例外FileNotFoundExceptionは報告されません。スローするには、捕捉または宣言する必要があります
			in = new FileInputStream(file);
			     ^
XMLtoSetProperty.java:55: エラー: 例外IOExceptionは報告されません。スローするには、捕捉または宣言する必要があります
			settings.loadFromXML(in);
			                    ^
エラー6個
--------------------------------------------------

VSCodeの出力内容でコードを修正できる方はあまりいないでしょう。javacコマンドであれば直すべき箇所が一目瞭然で一発修正できます。

開発速度への影響が大きいのでVSCodeでの実行がうまくいかない時は即コマンドで確認すべきだと痛感しました。

[Java] 99 OS名とLinuxディストリビューション名の取得

自製アプリのクロスプラットフォーム化にあたりOSやディストリビューションによってフォントサイズを変える必要が生じたため、以下のメソッドを作成して対応しました。

UbuntuやLinux Mint以外で”cat /etc/issue”コマンドにてディストリビューション名が分かるかどうかは不明です。

言語仕様とは言え、変数(フォントサイズ)を一々配列に格納するのは面倒です。

// Windows,Macはサイズ8,Ubuntuは7,Linux Mintは10に設定

public static int font_size(){
	String OS = System.getProperty("os.name").toLowerCase();
	int[] font_sizes = new int[1];
	if (OS.contains("linux")){
		try{
			Process p = Runtime.getRuntime().exec("cat /etc/issue");
			try{
				p.waitFor();
				InputStream is = p.getInputStream();
				InputStreamReader inputStreamReader = new InputStreamReader(is);
				Stream<String> streamOfString= new BufferedReader(inputStreamReader).lines();
				String str = streamOfString.collect(Collectors.joining());
								
				if (str.contains("Ubuntu")){
					int font_size = 7;
					font_sizes[0] = font_size;
				}else if (str.contains("Mint")){
					int font_size = 10;
					font_sizes[0] = font_size;
				}else{
					int font_size = 8;
					font_sizes[0] = font_size;
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	} else {
		int font_size = 8;
		font_sizes[0] = font_size;
	}
	return font_sizes[0];
}

[Java] 98 JColorChooserのshowDialogメソッドを自製

前回の続きです。

前の記事のコードではJcolorChooserダイアログの取消ボタンが効かず、変更した色のRGB値が返されてしまいます。そこでActionListenerとしてokListenerとcancelListenerを追加しました。

それぞれのアクションとして戻り値のRGBA値を作成しますが、public修飾子が使えずこれらをActionListenerの外に渡す方法が分からなくて少々苦労しました。

結局、初期設定で作成しておいたint配列color_caseに移し替えるという何とも泥臭い方法で取り出しました。Javaの仕様ではこうするしかないようです。

okListenerとcancelListenerを今回のように使っているコード例はGoogle検索上位では見あたらなかったのでアップしておきます。

<メソッドのみ>

static int[] showDialog(Component component, String title, Color initialColor) throws HeadlessException{
		int[] color_case = new int[4];
		JColorChooser chooser = new JColorChooser(initialColor != null ? initialColor : Color.white);

		String swatches = UIManager.getString("ColorChooser.swatchesNameText");
		String hsv = UIManager.getString("ColorChooser.hsvNameText");
		String hsl = UIManager.getString("ColorChooser.hslNameText");
		String rgb = UIManager.getString("ColorChooser.rgbNameText");
		String cmyk = UIManager.getString("ColorChooser.cmykNameText");

		List<String> list = Arrays.asList(hsv,hsl,rgb);

		for (AbstractColorChooserPanel p : chooser.getChooserPanels()) {
			if (!list.contains(p.getDisplayName())) {
				chooser.removeChooserPanel(p);
			}
		}
		
		ColorTracker tracker = new ColorTracker(chooser,initialColor);

		ActionListener okListener = new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int[] colors = tracker.getColor();
				color_case[0] = colors[0];
				color_case[1] = colors[1];
				color_case[2] = colors[2];
				color_case[3] = colors[3];
			}
		};

		ActionListener cancelListener = new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int[] colors = tracker.getInitial();
				color_case[0] = colors[0];
				color_case[1] = colors[1];
				color_case[2] = colors[2];
				color_case[3] = colors[3];
			}
		};

		// ダイアログを作成
		JDialog dialog = JColorChooser.createDialog(component, title, true, chooser, okListener, cancelListener);
		dialog.setVisible(true);

		return color_case;
	}

	static class ColorTracker implements Serializable{
		JColorChooser chooser;
		Color color;
		int red;
		int green;
		int blue;
		int alpha;
		int[] colors;
	  
		ColorTracker(JColorChooser Chooser,Color initialColor){
			this.chooser = Chooser;
			this.color = initialColor;
			
		}
	  
		int[] getColor(){
			this.color = this.chooser.getColor();

			colors = new int[4];
			colors[0] = this.color.getRed();
			colors[1] = this.color.getGreen();
			colors[2] = this.color.getBlue();
			colors[3] = this.color.getAlpha();

			return colors;
		}
		int[] getInitial(){
			colors = new int[4];
			colors[0] = this.color.getRed();
			colors[1] = this.color.getGreen();
			colors[2] = this.color.getBlue();
			colors[3] = this.color.getAlpha();

			return colors;
		}
	}

[Java] 97 JColorChooserクラス

自製アプリに色調整の機能を追加するためダイアログを作成しようとしましたが、取り掛かる前にJColorChooserという便利なクラスを見つけました。機能的にはこれで十分です。

下記コードは色調整ダイアログを表示するボタンのアクションです。listを書き換えると表示タブを変更・並べ替えできます。今回は”swatches”以外の4つのタブを選択しています。またデフォルトにある下段のプレビュー部を消してみました。

デフォルトの5つのタブから取捨選択したChooserはcreateDialogでダイアログを作成する際に引数として使用します。

自製showDialogメソッドはJColorChooser.showDialogメソッドとは異なりOKボタンを押した時のRGB値を返してくれないので、これを追跡して返すColorTrackerクラスを用意しました。GitHubにあったコードに手を入れて作成しました。

思いのほか手間が掛かり半日を要しましたが、C/C++で書く苦労を考えれば大分マシでしょう。

<ライブラリは省略>

public class AdjustButtonAction{
    public static void main(){
      adj_btn.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent e){
				if(e.getSource() == adj_btn){
					Color defaultColor = new Color(65,105,225);
					Color color = showDialog(parent, "色の調整", defaultColor);

					if(color == null) {
						System.out.println("選択されず");
					}else {
						System.out.println("R " + color.getRed());
						System.out.println("G " + color.getGreen());
						System.out.println("B " + color.getBlue());
        			}
				}
			}
		});
    }
	
	static Color showDialog(Component component, String title, Color initialColor) throws HeadlessException{
		JColorChooser chooser = new JColorChooser(initialColor != null ? initialColor : Color.white);
		
		// デフォルトの下段にあるプレビューを非表示にする
		chooser.setPreviewPanel(new JPanel());

		String swatches = UIManager.getString("ColorChooser.swatchesNameText");
		String hsv = UIManager.getString("ColorChooser.hsvNameText");
		String hsl = UIManager.getString("ColorChooser.hslNameText");
		String rgb = UIManager.getString("ColorChooser.rgbNameText");
		String cmyk = UIManager.getString("ColorChooser.cmykNameText");
		System.out.println("swatches " + swatches);
		System.out.println("hsv " + hsv);
		System.out.println("hsl " + hsl);
		System.out.println("rgb " + rgb);
		System.out.println("cmyk " + cmyk);

		// 色フォーマットのタブを選択
		List<String> list = Arrays.asList(hsv,hsl,rgb,cmyk);

		for (AbstractColorChooserPanel p : chooser.getChooserPanels()) {
			if (!list.contains(p.getDisplayName())) {
				chooser.removeChooserPanel(p);
			}
		}
	
		// ダイアログ作成
		ColorTracker ok = new ColorTracker(chooser);
		JDialog dialog = JColorChooser.createDialog(component, title, true, chooser, null, null);

		dialog.setVisible(true); 

		return ok.getColor();

	}
	static class ColorTracker implements ActionListener, Serializable{
		JColorChooser chooser;
		Color color;
	  
		ColorTracker(JColorChooser Chooser){
			this.chooser = Chooser;
		}
	  
		public void actionPerformed(ActionEvent e){
		}
	  
		Color getColor(){
			this.color = this.chooser.getColor();
			System.out.println("this.color " + this.color);
		return this.color;
		}
	}
}
--------------------------------------------------
出力
--------------------------------------------------
swatches サンプル(S)
hsv HSV(H)
hsl HSL(L)
rgb RGB(G)
cmyk CMYK
this.color java.awt.Color[r=65,g=105,b=225]
R 65
G 105
B 225