Почему переключатели неправильно отображаются в java.awt.Dialog на Mac, когда диалог модальный?
Вопрос
Я тестирую свое Java-приложение на Mac и столкнулся с очень странной проблемой. Флажки, которые появляются в модальном диалоге, отображаются неправильно, хотя немодальные диалоги работают нормально.
Например, скажем, у меня есть окно с 2 переключателями. Когда открывается диалоговое окно, выбирается первый. Когда я нажимаю на вторую кнопку, она внезапно выглядит так, как будто выбраны оба. Если щелкнуть мышью в любом другом месте диалогового окна, рендеринг будет исправлен, и будет отображаться только выбранная кнопка.
Следующий код воспроизводит это для меня:
package mactest;
import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.Dialog;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class Main {
public static void main(String[] args) {
boolean modal = false;
if(args.length > 0) {
modal = args[0].toLowerCase().equals("true");
}
TestDialog dlg = new TestDialog(new Frame(), modal);
dlg.setVisible(true);
}
private static class TestDialog extends Dialog {
private Checkbox cb1;
private Checkbox cb2;
private CheckboxGroup cbg;
public TestDialog(Frame owner, boolean modal) {
super(owner);
cbg = new CheckboxGroup();
cb1 = new Checkbox("One", true, cbg);
cb2 = new Checkbox("Two", false, cbg);
this.setLayout(new FlowLayout());
this.add(cb1);
this.add(cb2);
this.setModal(modal);
this.pack();
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
TestDialog.this.setVisible(false);
System.exit(0);
}
});
}
}
}
Если я назову это так:
java -cp MacTest.jar mactest.Main false
диалог не модальный и все работает нормально. Однако, если я скажу, что это модально:
java -cp MacTest.jar mactest.Main true
тогда возникают проблемы с рендерингом.
Я испробовал все уловки, которые только мог придумать, чтобы попытаться исправить проблему (сделать недействительными, doLayout, запрос фокуса, явную настройку состояния каждой кнопки, когда она выбрана и т. д.), но пока единственное, что я Я пришел к выводу, что это делает диалог не модальным. К сожалению, это не вариант в моем приложении.
Если это имеет значение, это на MacBook под управлением OS X 10.5 с Java 1.5.0_16.
Решение 2
Я нашел кое-что, что, кажется, исправило бы это, хотя это - уродливый взлом. Я добавил слушателей элемента для каждого из флажков. Когда они срабатывают, я изменяю размер окна на 1 пиксель, затем выполняю invokeLater () для pack () (мои диалоговые окна не меняются). Вот модифицированный тестовый код:
package mactest;
import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.Dialog;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Rectangle;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class Main {
public static void main(String[] args) {
boolean modal = false;
boolean tweak = false;
if(args.length > 0) {
modal = args[0].toLowerCase().equals("true");
}
if(args.length > 1) {
tweak = args[1].toLowerCase().equals("true");
}
TestDialog dlg = new TestDialog(new Frame(), modal, tweak);
dlg.setVisible(true);
}
private static class TestDialog extends Dialog {
private Checkbox cb1;
private Checkbox cb2;
private CheckboxGroup cbg;
public TestDialog(Frame owner, boolean modal, boolean tweak) {
super(owner);
cbg = new CheckboxGroup();
cb1 = new Checkbox("One", true, cbg);
cb2 = new Checkbox("Two", false, cbg);
this.setLayout(new FlowLayout());
this.add(cb1);
this.add(cb2);
this.setModal(modal);
this.pack();
if(tweak) {
cb1.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
onSelection();
}
});
cb2.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
onSelection();
}
});
}
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
TestDialog.this.setVisible(false);
System.exit(0);
}
});
}
private void onSelection() {
Rectangle bounds = this.getBounds();
this.setBounds(bounds.x, bounds.y, bounds.width + 1, bounds.height);
EventQueue.invokeLater(new Runnable() {
public void run() {
TestDialog.this.pack();
}
});
}
}
}
Для компонентов с изменяемым размером вам нужно сохранить предварительную настройку размера и восстановить ее вместо вызова pack ().
В окнах я иногда видел, как диалоговое окно мерцало, когда я менял выделение, хотя на Mac это было совсем не заметно.
Другие советы
Вы спрашиваете о флажках или радиокнопках? Вы упоминаете оба.
Чтобы создать область множественного исключения, вы должны использовать класс ButtonGroup