JTextPane в GridBagLayout не се държат по желания начин

Срещнах следния проблем в моята програма. Имам JPanel с GridBagLayout в рамките на JScrollPanel. Трябва да има следното поведение:

  1. Превъртането трябва да е възможно само вертикално.
  2. В JPanel редовете се добавят динамично. Тези редове имат две колони. И двете колони трябва да разделят пространството по равно.
  3. Всяко поле (колона/ред) на тази таблица е JTextPane, тъй като текстът може да се редактира и може да показва HTML. Ако текстът е твърде дълъг, той ще бъде обвит с ефекта, че височината на полето нараства.
  4. При преоразмеряване на прозореца се преоразмеряват и колоните.

Проблемът е, когато има дълъг текст:

  • Когато използвате JTextPane без PreferredSize, обвиването не работи и колоните не са разделени по равно. Задавайки Предпочитан размер, JTextPane изрязва текста във втория ред. JEditorPane също не работи.
  • Когато използвате JTextArea с активирано обвиване, тогава работи! Въпреки това не мога да покажа HTML. Освен това четвъртата точка не е изпълнена. При разширяване на прозореца полето също се преоразмерява. Но когато отново намалявате прозореца, той не се преоразмерява обратно.

Как мога да постигна желаното поведение и да избегна тези проблеми? Вече изчерпах всички възможности, за които се сещам.

Ето снимка на желаното поведение при използване на JTextPanes (но без HTML):

Ето снимка на желаното поведение при използване на ‹code›JTextPanes‹/code› (но без HTML)

Ето грешното поведение при използване на JTextPanes:

Ето грешното поведение при използване на JTextPanes:

И ето код за SSCCE:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.WindowConstants;

public class EditorTest extends JFrame {
    private JPanel jPanel1;
    private JPanel jPanel2;
    private JScrollPane jScrollPane1;
    private JTextPane jTextPane1;
    private JTextPane jTextPane2;

    public EditorTest() {
        initComponents();
    }

    private void initComponents() {
        GridBagConstraints gridBagConstraints;

        jScrollPane1 = new JScrollPane();
        jPanel2 = new JPanel();
        jPanel1 = new JPanel();
        jTextPane2 = new JTextPane();
        jTextPane1 = new JTextPane();

        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setPreferredSize(new Dimension(500, 500));
        getContentPane().setLayout(new GridBagLayout());

        jScrollPane1.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        jScrollPane1.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

        jPanel2.setBorder(BorderFactory.createEmptyBorder());
        jPanel2.setLayout(new BorderLayout());

        jPanel1.setLayout(new GridBagLayout());

        jTextPane2.setContentType("text/html"); 

        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 0.5;
        gridBagConstraints.insets = new Insets(0, 0, 3, 3);
        jPanel1.add(jTextPane2, gridBagConstraints);

        jTextPane1.setContentType("text/html");
        jTextPane1.setText("This is a very long text that also sometimes is "
                + "<span style=\"color:blue\">blue</span> and so on and so on.");
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 0.5;
        gridBagConstraints.insets = new Insets(0, 0, 3, 3);
        jPanel1.add(jTextPane1, gridBagConstraints);

        jPanel2.add(jPanel1, BorderLayout.NORTH);


        jScrollPane1.setViewportView(jPanel2);

        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        getContentPane().add(jScrollPane1, gridBagConstraints);

        pack();
    }                     

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                new EditorTest().setVisible(true);
            }
        });
    }            
}

Благодаря ви много за вашата помощ!

АКТУАЛИЗАЦИЯ1

За да направя желаното поведение по-ясно, създадох друга екранна снимка с JTextArea, както на първата снимка отгоре. Текстовите панели трябва да са в горната част и само толкова високо, колкото е необходимо (т.е. текстът). За да илюстрирате това поведение, промените и фона на текстовото поле.

въведете описание на изображението тук


person Rolch2015    schedule 24.03.2015    source източник
comment
Трябва да посочите предпочитания и максимален размер на jtextpane. Ширината трябва да е половината от вашия jpanel, а височината трябва да е тази по подразбиране. (т.е. Super.getPreferredSize().height).   -  person Sharcoux    schedule 25.03.2015
comment
Уважаеми @user1967800, благодаря ви за коментара! Настройката на setMaximumSize() няма ефект. Въпреки това, като зададете getPreferredSize() с параметрите, които предлагате, ширината се показва правилно, но височината запълва целия прозорец. Може би това е много близо! Имате ли друга идея как да регулирам височината сега?   -  person Rolch2015    schedule 25.03.2015


Отговори (2)


Мисля, че ме разбрахте погрешно, така че ето клас, който да ви покаже по-ясно:

private class MyJTextPane extends JTextPane {
    public Dimension getPreferredSize() {
        return new Dimension(245,super.getPreferredSize().height);
    }
    public Dimension getMaximumSize() {
        return getPreferredSize();
    }
}

Можете да използвате този клас във вашия SSCCE, за да видите как се държи.

Това е само за да ви даде представа как да използвате getMaximumSize и getPreferredSize, за да постигнете целта си. Това, което трябва да разберете е, че за дадена ширина методът по подразбиране getPreferredSize връща височината, необходима за показване на съдържанието на JTextPane.

Във вашия случай просто трябва да замените 245 с крайната ширина, която очаквате. Можете да използвате и функция, ако ширината зависи от други елементи.

Кажете ми, ако имате нужда от повече подробности.

person Sharcoux    schedule 26.03.2015
comment
Уважаеми @user1967800, благодаря ви много, това работи перфектно! След като прочетох публикацията ви, прочетох и други статии за preferredSize, maximumSize и т.н. и мисля, че вече го разбирам много по-добре. Научих много от вас! - person Rolch2015; 26.03.2015

Мисля, че кодирах това, което искахте.

Трябваше да задам предпочитан размер за JPanel вътре в екрана за превъртане. Ширината може да бъде каквато желаете. Височината ще трябва да се коригира за размера на JTextPanes.

Ето изображение на GUI.

Тест на редактора

И ето кода.

package com.ggl.testing;

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.WindowConstants;

public class EditorTest extends JFrame {
    private static final long serialVersionUID = 8019172274009058078L;

    private JPanel jPanel1;
    private JScrollPane jScrollPane1;
    private JTextPane jTextPane1;
    private JTextPane jTextPane2;

    public EditorTest() {
        initComponents();
    }

    private void initComponents() {
        GridBagConstraints gridBagConstraints;

        jScrollPane1 = new JScrollPane();
        jPanel1 = new JPanel();
        jTextPane2 = new JTextPane();
        jTextPane1 = new JTextPane();

        setTitle("Editor Test");
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        getContentPane().setLayout(new GridBagLayout());

        jScrollPane1
                .setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        jScrollPane1
                .setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

        jPanel1.setLayout(new GridLayout(0, 2));
        jPanel1.setPreferredSize(new Dimension(400, 400));

        jTextPane2.setContentType("text/html");
        jTextPane2
                .setText("<html>This is a very long text that also sometimes is "
                        + "<span style=\"color:green\">green</span> and so on and so on.");

        jTextPane1.setContentType("text/html");
        jTextPane1
                .setText("<html>This is a very long text that also sometimes is "
                        + "<span style=\"color:blue\">blue</span> and so on and so on.");

        jPanel1.add(jTextPane1);
        jPanel1.add(jTextPane2);

        jScrollPane1.setViewportView(jPanel1);

        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        getContentPane().add(jScrollPane1, gridBagConstraints);

        pack();
    }

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                new EditorTest().setVisible(true);
            }
        });
    }
}
person Gilbert Le Blanc    schedule 24.03.2015
comment
Уважаеми @GilbertLeBlanc, благодаря ви за бързия отговор! Проучих внимателно отговора ви и експериментирах с него. За съжаление не получавам желаното поведение. JTextPane трябва да е най-отгоре и не по-високо от необходимото (т.е. текста), защото други редове могат да се добавят динамично. Освен това, ако е възможно, бих искал да използвам GirdBagLayout за JTextPanes. Съжалявам, ако въпросът ми не е бил достатъчно ясен, ще го актуализирам отново! Мислите ли, че това е възможно? Искрено оценявам вашата помощ и усилия. - person Rolch2015; 24.03.2015
comment
Уважаеми @GilbertLeBlanc, актуализирах въпроса с друга екранна снимка. Благодаря ти! - person Rolch2015; 25.03.2015