Я использую компонент JScrollNavigator
, описанный здесь, чтобы предоставить окно навигации на большой «холстовый» компонент САПР, который я встроил в файл JScrollPane
.
Я попытался адаптировать JScrollNavigator
для рисования эскиза холста, чтобы предоставить пользователю дополнительный контекст. Однако это действие приводит к повреждению рендеринга основного фрейма моего приложения. В частности, это действие вызова paint(Graphics)
для компонента окна просмотра (т. е. моего основного холста), передачи объекта Graphics
, созданного BufferedImage
, что вызывает последующее повреждение отображения; если я закомментирую эту строку, все будет работать нормально.
Ниже приведен переопределенный метод paintComponent
JScrollNavigator
:
@Override
protected void paintComponent(Graphics g) {
Component view = jScrollPane.getViewport().getView();
BufferedImage img = new BufferedImage(view.getWidth(), view.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
// Paint JScrollPane view to off-screen image and then scale.
// It is this action that causes the display corruption!
view.paint(g2d);
g2d.drawImage(img, 0, 0, null);
Image scaled = img.getScaledInstance(getWidth(), getHeight(), 0);
super.paintComponent(g);
g.drawImage(scaled, 0, 0, null);
}
У кого-нибудь есть какие-либо предположения относительно причины коррупции? Я бы подумал, что рисование внеэкранного изображения не должно влиять на существующие операции рисования.
ИЗМЕНИТЬ
Чтобы предоставить некоторые дополнительные детали: JScrollNavigator
образует подпанель слева от JSplitPane
. JScrollPane
, связанный с навигатором, находится справа. «Повреждение» приводит к тому, что сплиттер больше не отображается, а полосы прокрутки не видны (они кажутся белыми). Если я изменю размер JFrame
, раздел JMenu
также станет белым. Если я пытаюсь использовать навигатор или взаимодействовать с полосами прокрутки, они становятся видимыми, но сплиттер остается белым. Это как если бы настройки непрозрачности различных компонентов были затронуты рендерингом окна просмотра в закадровое изображение.
Кроме того, если я заставлю JScrollNavigator
появиться в совершенно отдельном JDialog
, все будет работать правильно.
ИЗМЕНИТЬ 2
Я могу воспроизвести проблему последовательно, выполнив следующие действия:
Добавьте JMenuBar
к mFrame
:
JMenuBar bar = new JMenuBar();
bar.add(new JMenu("File"));
mFrame.setJMenuBar(bar);
В методе main()
из JScrollNavigator
замените:
jsp.setViewportView(textArea);
... с участием:
jsp.setViewportView(new JPanel() {
{
setBackground(Color.GREEN);
setBorder(BorderFactory.createLineBorder(Color.BLACK, 5));
}
});
Убедитесь, что JScrollNavigator
встроена как панель в mFrame
, а не отображается как отдельная JDialog
:
mFrame.add(jsp, BorderLayout.CENTER);
mFrame.add(nav, BorderLayout.NORTH);
Теперь, когда приложение запускается, JMenuBar
больше не отображается; акт рисования представления (т.е. зеленого JPanel
с толстой черной рамкой) для Graphics2D
, возвращаемого BufferedImage.createGraphics()
, на самом деле, кажется, отображает его на экране, возможно, из верхнего левого угла JFrame, таким образом скрывая другие компоненты. Кажется, это происходит только в том случае, если в качестве окна просмотра используется JPanel
, а не другой компонент, такой как JTextArea
, JTable
и т. д.
ИЗМЕНИТЬ 3
Похоже, у этого человека возникла та же проблема (хотя решение не опубликовано): http://www.javaworld.com/community/node/2894/
ИЗМЕНИТЬ 4
Вот методы main
и paintComponent
, которые приводят к воспроизводимой ошибке, описанной в Редактировании 2:
public static void main(String[] args) {
JScrollPane jsp = new JScrollPane();
jsp.setViewportView(new JPanel() {
{
setBackground(Color.GREEN);
setBorder(BorderFactory.createLineBorder(Color.BLACK, 5));
}
});
JScrollNavigator nav = new JScrollNavigator();
nav.setJScrollPane(jsp);
JFrame mFrame = new JFrame();
JMenuBar bar = new JMenuBar();
bar.add(new JMenu("File"));
mFrame.setJMenuBar(bar);
mFrame.setTitle("JScrollNavigator Test");
mFrame.setSize(800, 600);
mFrame.setLayout(new GridLayout(1, 2));
mFrame.add(jsp);
mFrame.add(nav);
Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
mFrame.setLocation((screenDim.width - mFrame.getSize().width) / 2, (screenDim.height - mFrame.getSize().height) / 2);
mFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mFrame.setVisible(true);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Component view = jScrollPane.getViewport().getView();
if (img == null) {
GraphicsConfiguration gfConf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
img = new BufferedImage(view.getWidth(), view.getHeight(), BufferedImage.TYPE_INT_ARGB);
}
Graphics2D g2d = img.createGraphics();
view.paint(g2d);
Image scaled = img.getScaledInstance(getWidth(), getHeight(), 0);
g.drawImage(scaled, 0, 0, null);
}
ИЗМЕНИТЬ 5
Кажется, что у других возникают проблемы с воссозданием точной проблемы. Я бы попросил людей запустить код, вставленный здесь. Когда я впервые запускаю этот пример, я вижу следующее:
Ни JScrollNavigator, ни JMenuBar не были нарисованы; эти области кадра прозрачны.
После изменения размера вижу следующее:
JMenuBar
все еще не нарисовано, и кажется, что JPanel
в какой-то момент был отрендерен в (0,0) (где должен быть JMenuBar
). Вызов view.paint
внутри paintComponent
является прямой причиной этого.
super.paintComponent(g);
в начале переопределенного методаpaintComponent
. - person Xeon   schedule 31.07.2012