お世話になります。
タイトルの通り、javaの機能で印刷ダイアログを表示させる機能があるのですが、そのダイアログの中にあるプロパティボタンを非表示、または使用不可にしたいです。
ダイアログを表示する際に使用しているメソッドはServiceUI.printDialogになります。
ServiceDialogのメソッドの一覧を見てもプロパティボタンを操作するようなメソッドもなく、ボタンがprivateで宣言されていることも確認しました。
無理なら無理でかまわないのですが、出来たらどうにかしたいと思っております。
ServiceUIとServiceDialogのソースを丸ごとコピーして、そのクラスを使用するという方法も試しましたがエラーが出てダイアログが表示されませんでした。
以下実行した際のエラー文になります。
Exception in thread "AWT-EventQueue-0" java.lang.Error: Fatal: Resource for ServiceUI is broken; there is no tab.general.vkMnemonic key in resource
すみませんがどなたかお力添えを頂ければと思います。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答2件
0
質問はクローズされてしまいましたが、実装例を載せてみますのでよかったら参考にしてください。ただトリッキーな実装ですので不用意に使わない方がよいです。(質問者の方はその点おわかりと思いますが)実装に不備などありましたらご容赦ください。
- パッチのトリガー
基本的には印刷を行うアクションソース(サンプルコードの例では"PRINT"ボタン)のfocusLostイベントを捕捉して、その契機でパッチを試みます。しかし印刷ダイアログが表示される前に他のウィンドウをアクティベートするとfocusLost発火時点ではまだ印刷ダイアログがないかも知れません。よって安全のためパッチが完了するまでは0.5秒おきに繰り返しパッチを試みます。
- パッチ可能対象の特定
印刷ダイアログはJRE内部で生成されるため質問者さんが悩んでおられたように自然な形でのパッチはできません。そこでWindowクラスを利用してJavaで生成した全てのWindowを調べ、その中にdisplayableかつ目的のクラスのwindowを探すという方法でダイアログのインスタンスを特定します。displayableをチェックすることは重要です。peerがない状態のWindowインスタンスはそれが本当に現在表示中のダイアログのインスタンスとは限らないからです。
- プロパティボタンの探し方
パッチ対象のボタンはsun.print.ServiceDialog内のタブコントロールの一つにぶら下がるsun.print.ServiceDialog.PrintServicePanelの下にあります。前者はpublicなクラスなのでisinstanceofで簡単に同定できますが、後者はprivateクラスなのでServiceDialogのComponent階層を下に辿りながらクラスのCanonicalNameを比較することで同定します。PrintServicePanelが見つかったらリフレクションで特定のフィールドにアクセスしボタンの実体が得られます。
- パッチ機能のクラス
本体のアプリケーションのあちこちに実装を分散させるとよくないのでサンプルではDialogWatcherクラスの中に全てのパッチ関連機能を閉じ込めてあります。印刷ダイアログを表示する前後でこのクラスに対してパッチ開始とパッチ終了を指示するような作りです。パッチ終了の指示は通常必要ないはずですが念のため行っています。
以下実装サンプルです。
java
1package test5; 2 3import java.awt.BorderLayout; 4import java.awt.Component; 5import java.awt.Container; 6import java.awt.Dimension; 7import java.awt.GraphicsConfiguration; 8import java.awt.GraphicsDevice; 9import java.awt.GraphicsEnvironment; 10import java.awt.Window; 11import java.awt.event.ActionEvent; 12import java.awt.event.ActionListener; 13import java.awt.event.FocusEvent; 14import java.awt.event.FocusListener; 15import java.lang.reflect.Field; 16 17import javax.print.DocFlavor; 18import javax.print.PrintService; 19import javax.print.PrintServiceLookup; 20import javax.print.ServiceUI; 21import javax.print.attribute.HashPrintRequestAttributeSet; 22import javax.print.attribute.PrintRequestAttributeSet; 23import javax.print.attribute.standard.MediaSizeName; 24import javax.swing.AbstractAction; 25import javax.swing.JButton; 26import javax.swing.JFrame; 27import javax.swing.JPanel; 28import javax.swing.Timer; 29 30public class Test5 extends JFrame { 31 public static void main(String[] args) { 32 new Test5().setVisible(true); 33 } 34 35 JButton printButton; 36 37 Test5() { 38 super("Test5"); 39 JPanel mainPanel = (JPanel)getContentPane(); 40 printButton = new JButton(new AbstractAction("PRINT") { 41 @Override 42 public void actionPerformed(ActionEvent e) { 43 doPrint(e); 44 } 45 }); 46 printButton.setPreferredSize(new Dimension(200, 100)); 47 mainPanel.add(printButton, BorderLayout.CENTER); 48 49 setDefaultCloseOperation(EXIT_ON_CLOSE); 50 pack(); 51 } 52 53 private void doPrint(ActionEvent e) { 54 Component control = (Component)e.getSource(); 55 GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 56 GraphicsDevice[] gds = ge.getScreenDevices(); 57 GraphicsConfiguration gc = gds[0].getDefaultConfiguration(); 58 DocFlavor flavor = null; 59 PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet(); 60 attributes.add(MediaSizeName.ISO_A4); 61 PrintService[] services = PrintServiceLookup.lookupPrintServices(flavor, attributes); 62 63 DialogWatcher.watch(true, control); 64 try { 65 ServiceUI.printDialog(gc, 100, 100, services, services[0], flavor, attributes); 66 } finally { 67 DialogWatcher.watch(false, control); 68 } 69 } 70 71 static class DialogWatcher implements FocusListener, ActionListener { 72 static DialogWatcher singleton = new DialogWatcher(); 73 74 static void watch(boolean watching, Component c) { 75 singleton._watch(watching, c); 76 } 77 78 boolean watching = false; 79 Component component; 80 Timer timer; 81 82 void _watch(boolean watching, Component c) { 83 if (this.watching != watching) { 84 this.watching = watching; 85 if (watching) { 86 System.out.println("timer start"); 87 timer = new Timer(500, this); 88 timer.setRepeats(true); 89 timer.start(); 90 c.addFocusListener(this); 91 this.component = c; 92 } else { 93 System.out.println("timer stop"); 94 timer.stop(); 95 timer = null; 96 c.removeFocusListener(this); 97 } 98 } 99 } 100 101 @Override 102 public void focusGained(FocusEvent e) { 103 System.out.format("focus gained src=%s\n", e.getSource().getClass()); 104 System.out.flush(); 105 } 106 107 @Override 108 public void focusLost(FocusEvent e) { 109 System.out.format("focus lost src=%s\n", e.getSource().getClass()); 110 System.out.flush(); 111 checkWindows(); 112 } 113 114 @Override 115 public void actionPerformed(ActionEvent e) { 116 checkWindows(); 117 } 118 119 synchronized void checkWindows() { 120 if (!watching) 121 return; 122 sun.print.ServiceDialog dialog = null; 123 Window[] windows = Window.getWindows(); 124 for (Window win : windows) { 125 if (win.isDisplayable() && win instanceof sun.print.ServiceDialog) { 126 dialog = (sun.print.ServiceDialog)win; 127 System.out.format("we found the print dialog : %s\n", dialog.getClass()); 128 patch(dialog.getContentPane()); 129 _watch(false, component); 130 break; 131 } 132 } 133 } 134 135 static String ClassNameToPatch = "sun.print.ServiceDialog.PrintServicePanel"; 136 137 void patch(Container container) { 138 if (!container.getClass().getCanonicalName().equals(ClassNameToPatch)) { 139 for (Component c : container.getComponents()) { 140 if (c instanceof Container) { 141 patch((Container)c); 142 } 143 } 144 } else { 145 System.out.println("we found the JPanel to patch"); 146 Class<?> clz = container.getClass(); 147 try { 148 Field field = clz.getDeclaredField("btnProperties"); 149 field.setAccessible(true); 150 JButton button = (JButton)field.get(container); 151 button.setEnabled(false); 152 System.out.println("patch completed"); 153 } catch (NoSuchFieldException | SecurityException 154 | ClassCastException 155 | IllegalArgumentException | IllegalAccessException ex) { 156 System.err.println("reflection failed : " + ex.getMessage()); 157 } 158 } 159 } 160 } 161}
投稿2016/11/02 09:55
編集2016/11/02 09:59総合スコア18394
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/11/03 02:37
2016/11/07 00:28
0
ベストアンサー
ソースからボタン名の決め方などがわかるのでComponent階層を辿ってボタン名を頼りに探すという方法も使えそうですがswingにもう手が入らないであろうことを考えるとxa051さんがコメントされているようにリフレクションで直接フィールドをアクセスして求めてしまってもよいのかも知れません。その辺の判断はご自分で・・・
printDialogはダイアログを生成してshowまでやってしまうので、これをそのまま使うならボタンに対するパッチ処理は何かのイベントを契機にして行うなど若干トリッキーなことをしないといけないように思います。
投稿2016/10/28 09:26
総合スコア18394
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/10/31 02:38
2016/10/31 02:52
2016/11/01 06:43
2016/11/01 07:52
2016/11/02 05:14
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。