Хорошо, у вас было три вопроса:
Первый: Причина, по которой ваше окно маленькое, заключается в том, что вы используете jf.pack () вместе с макетом границы,что делает ваш JFrame размером, необходимым для отображения всего компонента, который он содержит, без дополнительного пространства вокруг.Вы можете установить макет в null и потерять часть jf.pack (), но это обычно не рекомендуемая практика.
Second: Окно всплывает во второй раз, потому что вы 'там создается второй экземпляр того же объекта в вашем слушателе:
job.setPrintable( new Printer() );
Часть "new Printer ()" создает другой объект Printer, который снова вызывает создание пользовательского интерфейса и т. д.
Вы можете создать внутренний класс вместо анонимного, чтобы иметь возможность использовать this для ссылки на текущий объект Printer.
Ваш метод hookUpEvents () будет выглядеть примерно так:
public void hookUpEvents() {
MyActionListener mal = new MyActionListener();
print.addActionListener(mal); {
}
Затем, где-нибудь еще в том же классе создайте внутренний класс следующим образом:
private class MyActionListener implements ActionListener{
public void actionPerformed(ActionEvent ae) {
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(Printer.this);
boolean doPrint = job.printDialog();
if( doPrint ) {
try {
job.print();
}
catch( PrinterException exc) {
System.out.println( exc );
}
}
else {
System.out.println("You cancelled the print");
}
}
}
Третий: Метод print () вызывается, когдавы вводите: "job.print ()", так как вы переопределяете метод из интерфейса.Тот, что в интерфейсе, на самом деле никогда не вызывается, так как вместо него вызывается ваш, что вы и хотите, поскольку вы определили, что он должен был делать.
Надеюсь, теперь это отвечает на ваши вопросы.
Редактировать: Я только что протестировал нечто подобное, и я думаю, что вы можете просто напечатать Printer.this в анонимном классе, чтобы заставить его работать, вместо создания внутреннего класса, который заставил бы вас изменить намного меньше кода.