0

次のように、本質的にテーブルのように見えるものを JTextPane に出力したいと思います。

テーブルプリントアウト

私の出力が現在どのように見えるかは次のとおりです。

私の現在の出力

ご覧のとおり、列は実際にはまったく整列していません。ただし、コンソールでは完璧で、次のようになります。

コンソールの印刷

(少し切れていますが、要点はわかります。整列しています!)

これを行うために、 https://github.com/htorun/dbtableprinterからいくつかのコードを借りています。ただし、コードはコンソールへの出力を中心に構築されているため、出力をコンソールに表示したくないため、コード、つまり print メソッドで動作するようにいくつかのビットを変換しています。print と println の代わりに、GUI クラスから 2 つのメソッドを呼び出しています。


//to replace print


public void printTableText(String toPrint){
    try {
        doc.insertString(doc.getLength(), toPrint, null);
    } catch (BadLocationException ex) {
        ex.printStackTrace();
    }
}



//to replace println

public void printText(String toPrint){
    try {
        toPrint = "\n" +  toPrint;
        doc.insertString(doc.getLength(), toPrint, null);
    } catch (BadLocationException ex) {
        ex.printStackTrace();
    }
}

基本的に、彼らのコードは JDBC テーブルのメタデータを解析して、特定のクエリの行数、列数、およびそれぞれのデータ型を取得し、列幅、パディングなどを設定して、本質的にコンソールに出力されるテーブル ビューをフォーマットします。 . 次のコードでそれを行います: (上記のメソッドを使用した印刷関連のコードは私のものであり、それ以外はすべてそうではありません)


 public void printResultSet(ResultSet rs, int maxStringColWidth) {
        try {
            if (rs == null) {
                System.err.println("DBTablePrinter Error: Result set is null!");
                return;
            }
            if (rs.isClosed()) {
                System.err.println("DBTablePrinter Error: Result Set is closed!");
                return;
            }
            if (maxStringColWidth < 1) {
                System.err.println("DBTablePrinter Info: Invalid max. varchar column width. Using default!");
                maxStringColWidth = DEFAULT_MAX_TEXT_COL_WIDTH;
            }

            // Get the meta data object of this ResultSet.
            ResultSetMetaData rsmd;
            rsmd = rs.getMetaData();

            // Total number of columns in this ResultSet
            int columnCount = rsmd.getColumnCount();

            // List of Column objects to store each columns of the ResultSet
            // and the String representation of their values.
            List<Column> columns = new ArrayList<>(columnCount);

            // List of table names. Can be more than one if it is a joined
            // table query
            List<String> tableNames = new ArrayList<>(columnCount);

            // Get the columns and their meta data.
            // NOTE: columnIndex for rsmd.getXXX methods STARTS AT 1 NOT 0
            for (int i = 1; i <= columnCount; i++) {
                Column c = new Column(rsmd.getColumnLabel(i),
                        rsmd.getColumnType(i), rsmd.getColumnTypeName(i));
                c.setWidth(c.getLabel().length());
                c.setTypeCategory(whichCategory(c.getType()));
                columns.add(c);

                if (!tableNames.contains(rsmd.getTableName(i))) {
                    tableNames.add(rsmd.getTableName(i));
                }
            }

            // Go through each row, get values of each column and adjust
            // column widths.
            int rowCount = 0;
            while (rs.next()) {

                // NOTE: columnIndex for rs.getXXX methods STARTS AT 1 NOT 0
                for (int i = 0; i < columnCount; i++) {
                    Column c = columns.get(i);
                    String value;
                    int category = c.getTypeCategory();

                    if (category == CATEGORY_OTHER) {

                        // Use generic SQL type name instead of the actual value
                        // for column types BLOB, BINARY etc.
                        value = "(" + c.getTypeName() + ")";

                    } else {
                        value = rs.getString(i+1) == null ? "NULL" : rs.getString(i+1);
                    }
                    switch (category) {
                        case CATEGORY_DOUBLE:

                            // For real numbers, format the string value to have 3 digits
                            // after the point. THIS IS TOTALLY ARBITRARY and can be
                            // improved to be CONFIGURABLE.
                            if (!value.equals("NULL")) {
                                Double dValue = rs.getDouble(i+1);
                                value = String.format("%.3f", dValue);
                            }
                            break;

                        case CATEGORY_STRING:

                            // Left justify the text columns
                            c.justifyLeft();

                            // and apply the width limit
                            if (value.length() > maxStringColWidth) {
                                value = value.substring(0, maxStringColWidth - 3) + "...";
                            }
                            break;
                    }

                    // Adjust the column width
                    c.setWidth(value.length() > c.getWidth() ? value.length() : c.getWidth());
                    c.addValue(value);
                } // END of for loop columnCount
                rowCount++;

            } // END of while (rs.next)

            /*
            At this point we have gone through meta data, get the
            columns and created all Column objects, iterated over the
            ResultSet rows, populated the column values and adjusted
            the column widths.

            We cannot start printing just yet because we have to prepare
            a row separator String.
             */

            // For the fun of it, I will use StringBuilder
            StringBuilder strToPrint = new StringBuilder();
            StringBuilder rowSeparator = new StringBuilder();

            /*
            Prepare column labels to print as well as the row separator.
            It should look something like this:
            +--------+------------+------------+-----------+  (row separator)
            | EMP_NO | BIRTH_DATE | FIRST_NAME | LAST_NAME |  (labels row)
            +--------+------------+------------+-----------+  (row separator)
             */

            // Iterate over columns
            for (Column c : columns) {
                int width = c.getWidth();

              // Center the column label
                String toPrint;
                String name = c.getLabel();
                int diff = width - name.length();

                if ((diff%2) == 1) {
                    // diff is not divisible by 2, add 1 to width (and diff)
                    // so that we can have equal padding to the left and right
                    // of the column label.
                    width++;
                    diff++;
                    c.setWidth(width);
                }

                int paddingSize = diff/2; // InteliJ says casting to int is redundant.

                // Cool String repeater code thanks to user102008 at stackoverflow.com
             
                String padding = new String(new char[paddingSize]).replace("\0", " ");

                toPrint = "| " + padding + name + padding + " ";
              // END centering the column label

                strToPrint.append(toPrint);

                rowSeparator.append("+");
                rowSeparator.append(new String(new char[width + 2]).replace("\0", "-"));
            }

            String lineSeparator = System.getProperty("line.separator");

            // Is this really necessary ??
            lineSeparator = lineSeparator == null ? "\n" : lineSeparator;

            rowSeparator.append("+").append(lineSeparator);

            strToPrint.append("|").append(lineSeparator);
            strToPrint.insert(0, rowSeparator);
            strToPrint.append(rowSeparator);

            StringJoiner sj = new StringJoiner(", ");
            for (String name : tableNames) {
                sj.add(name);
            }

            String info = "Printing " + rowCount;
            info += rowCount > 1 ? " rows from " : " row from ";
            info += tableNames.size() > 1 ? "tables " : "table ";
            info += sj.toString();

            window.printTableText(info);
            System.out.println(info);

            // Print out the formatted column labels
            System.out.print(strToPrint.toString());
            window.printTableText(strToPrint.toString());

            String format;

            // Print out the rows
            for (int i = 0; i < rowCount; i++) {
                for (Column c : columns) {

                    // This should form a format string like: "%-60s"
                    format = String.format("| %%%s%ds ", c.getJustifyFlag(), c.getWidth());
                    System.out.print(
                            String.format(format, c.getValue(i))
                    );
                    window.printTableText(String.format(format, c.getValue(i)));
                }

                System.out.println("|");
                System.out.print(rowSeparator);
                window.printText("|");
                window.printTableText(String.valueOf(rowSeparator));
            }

            System.out.println();

            /*
                Hopefully this should have printed something like this:
                +--------+------------+------------+-----------+--------+-------------+
                | EMP_NO | BIRTH_DATE | FIRST_NAME | LAST_NAME | GENDER |  HIRE_DATE  |
                +--------+------------+------------+-----------+--------+-------------+
                |  10001 | 1953-09-02 | Georgi     | Facello   | M      |  1986-06-26 |
                +--------+------------+------------+-----------+--------+-------------+
                |  10002 | 1964-06-02 | Bezalel    | Simmel    | F      |  1985-11-21 |
                +--------+------------+------------+-----------+--------+-------------+
             */

        } catch (SQLException e) {
            System.err.println("SQL exception in DBTablePrinter. Message:");
            System.err.println(e.getMessage());
        }
    }

コンソール出力が完璧であるという事実を考えると、私が到達した結論は、私の印刷方法、または私が借りた DBTablePrinter クラスで使用される書式設定を StyledDocuments が処理する方法に問題があるということです。私は JTextPanes と StyledDocuments を初めて使用するので、ここで気付いていない簡単なことが起こっているだけかもしれません。

4

0 に答える 0