Метки вершин прорисовываются за пределами вершин, над полосами прокрутки и другими компонентами, когда setLabelsClipped имеет значение true.

Я некоторое время работал с JGraph, и, похоже, возникает проблема с рисованием, когда вы устанавливаете для обрезки метки значение true:

Пример перерисовки

В следующем упрощённом примере показана проблема в живом приложении, с которым можно повозиться:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;

import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.view.mxGraph;

/** it's an app! */
public class GraphApp extends JFrame {
    private mxGraph graph;
    private mxGraphComponent graphComponent;
    private boolean labelsClipped = false;

    /** @return the splitpane */
    public JSplitPane getSplitpane() {
        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        graph = new mxGraph();
        graph.getModel().beginUpdate();
        graph.removeCells(graph.getChildCells(graph.getDefaultParent(), true, true));
        for (int i = 0; i < 10; i++)
            graph.insertVertex(null, null, "very_very_long_vertex_" + i, 10 * i, 10 * i, 100, 50);
        graph.getModel().endUpdate();
        graph.setLabelsClipped(labelsClipped);
        graphComponent = new mxGraphComponent(graph);
        JTextArea area = new JTextArea("There's overpaint below this text."); //$NON-NLS-1$
        splitPane.add(graphComponent, JSplitPane.LEFT);
        splitPane.add(area, JSplitPane.RIGHT);
        splitPane.setDividerLocation(70);
        return splitPane;
    }

    private JButton getButton() {
        JButton button = new JButton(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                labelsClipped = !labelsClipped;
                graph.setLabelsClipped(labelsClipped);
                GraphApp.this.repaint();
            }
        });
        button.setText("Swap setLabelsClipped");
        return button;
    }

    private JPanel getPanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.add(getSplitpane(), BorderLayout.CENTER);
        panel.add(getButton(), BorderLayout.SOUTH);
        return panel;
    }

    public static void main(String[] args) {
        GraphApp app = new GraphApp();
        app.add(app.getPanel());
        app.setPreferredSize(new Dimension(300, 100));
        app.setVisible(true);
        app.pack();
    }
}

Также интересно отметить, что перерисовка происходит только в пределах вершины. Вот имена с обрезанием:

Не обрезано

И с обрезкой:

Обрезано

Сейчас я изучаю источник JGraphx, чтобы понять, в чем проблема. Кто-нибудь работал над этим раньше? Очевидно, что настройка graph.setLabelsClipped(false) работает вокруг этого, но я бы не хотел, чтобы мои метки вершин выходили за границы моих вершин.


person Amish    schedule 13.09.2013    source источник
comment
Это в JGraphX ​​1.12.0.2. Я загружаю последнюю версию, чтобы узнать, исправлена ​​ли она в более поздних версиях.   -  person Amish    schedule 13.09.2013
comment
Похоже, он все еще существует в jgraphx-2_1_1_2.   -  person Amish    schedule 13.09.2013


Ответы (1)


Я нашел, в чем проблема.

Из com.mxgraph.view.mxGraph, если вы добавите этот небольшой код рисования, вы увидите, что клипу неправильно присваивается прямоугольник, который, как показано в моем примере, может находиться за пределами фактического компонента графика.

        if (clippedCanvas instanceof mxGraphics2DCanvas)
        {
            System.out.println("setting new clip");
            Graphics g = ((mxGraphics2DCanvas) clippedCanvas).getGraphics();
            clip = g.getClip();
            g.setClip(newClip);
            ((mxGraphics2DCanvas) clippedCanvas).paintRectangle(((mxGraphics2DCanvas) clippedCanvas).getGraphics().getClipBounds(), Color.GREEN, Color.WHITE);
        }

Если мы закрасим область отсечения, с которой работает метка, мы увидим, в чем заключается проблема.

Фальшивая область отсечения

На самом деле мы должны рисовать только пересечение исходного холста и нового прямоугольника отсечения. На этом изображении показано, каким был обрезающий прямоугольник до того, как его затоптал новый:

Исходная область отсечения

Исправление для этого простое:

        if (clippedCanvas instanceof mxGraphics2DCanvas)
        {
            Graphics g = ((mxGraphics2DCanvas) clippedCanvas).getGraphics();
            clip = g.getClip();
            if (clip instanceof Rectangle)
            {
                g.setClip(newClip.intersection((Rectangle) clip));
            }
            else
            {
                g.setClip(newClip);
            }
        }

Мне было бы интересно услышать, сделал ли исходный код настройку клипа так, как это было сделано намеренно. Я как-то сомневаюсь.

Мое исправление также по умолчанию использует их реализацию в случае, если кто-то делает что-то странное со своими формами клипа, как своего рода CYA. Вероятно, в этом нет необходимости, так как отсечение не гарантирует работу с чем-либо, кроме прямоугольников:

http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/Graphics.html#setClip(java.awt.Shape)

Похоже, что код находится здесь, на github, поэтому, надеюсь, я смогу получить исправление там:

https://github.com/jgraph/jgraphx

person Amish    schedule 13.09.2013