Привет! Я использую JGraphX для создания своего рода Java-редактора графических приложений.Приложение в целом работает нормально и как задумано при нормальных обстоятельствах.В общем, у меня есть класс Editor, который содержит все необходимые объявления для графа, как показано в примере кода ниже.
инициализация графа и переопределение некоторых его методов
public class Editor extends JFrame implements Serializable {
Handler handler;
JTabbedPane tabPane;
mxGraphComponent graphComponent;
EntityDataTable dataTable;
protected static mxGraph graph = new mxGraph() {
// Overrides method to disallow edge label editing
public boolean isCellEditable(Object cell) {
if (cell instanceof mxCell) {
mxCell c = (mxCell) cell;
if (c.isEdge()) {
return false;
} else {
return false;
}
}
return false;
}
// Overrides method to disallow edge selection
public boolean isCellSelectable(Object cell)
{
if (model.isEdge(cell))
{
return false;
}
return super.isCellSelectable(cell);
}
// Overrides method to provide a cell label in the display
public String convertValueToString(Object cell) {
if (cell instanceof mxCell) {
Object value = ((mxCell) cell).getValue();
if (value instanceof Element) {
Element elt = (Element) value;
// String tag = elt.getTagName();
String tag = elt.getAttribute("name");
return tag;
}
}
return super.convertValueToString(cell);
}
public String getToolTipForCell(Object cell){
return "Double Click to Edit";
}
};
...
ограничивает определенные отмены событий
protected mxEventSource.mxIEventListener undoHandler = new mxEventSource.mxIEventListener(){
public void invoke(Object source, mxEventObject evt)
{
mxUndoableEdit evt1 = (mxUndoableEdit) evt.getProperty("edit");
List<mxUndoableEdit.mxUndoableChange> changes = evt1.getChanges();
Object[] temp = graph.getSelectionCellsForChanges(changes);
boolean islegal = true;
for (int i = 0; i < temp.length; i++)
{
mxCell cell = (mxCell)temp[i];
String value = cell.getValue().toString();
if (value.equals("subprocess")||value.equals("optional")||value.equals("parallel")||value.equals("synchronous")||value.equals("activating")||value.equals("deactivating")){
//System.out.println("is not legal");
islegal = false;
}
}
for (int i = 0; i < changes.size(); i++){
if (changes.get(i).toString().contains("mxValueChange")){
islegal = false;
}
}
graph.setSelectionCells(graph.getSelectionCellsForChanges(changes));
if (islegal == true){
undoManager.undoableEditHappened((mxUndoableEdit) evt
.getProperty("edit"));
}else{
// System.out.println("illegal undo");
}
}};
...
protected boolean modified = false;
protected mxGraphOutline graphOutline;
protected JPanel actionPane;
mxUndoManager undoManager;
public Editor() {
handler = new Handler(this);
dataTable = new EntityDataTable(handler);
initGUI();
initGraphSettings();
}
public Editor(SaveData saveData) {
handler = new Handler(this);
dataTable = new EntityDataTable(handler);
initGUI();
initGraphSettings();
//erst alle entities erstellen und submitten, dann alle verbindungselemente zu den entities hinzufügen und nochmal submit
//Load entities
ArrayList<DataSaveElement> saveDataList = saveData.getSaveData(); for (int i = 0; i < saveDataList.size(); i++){
System.out.println("Loaded "+saveDataList.get(i).getType()+" "+saveDataList.get(i).getName());
if (saveDataList.get(i).getType().equals("Process")){
ProcessPopUp temp = new ProcessPopUp(handler, this);
temp.setGlobalID(saveDataList.get(i).getGlobalID());
temp.setName(saveDataList.get(i).getName());
temp.setDesc(saveDataList.get(i).getDescription());
temp.setType(saveDataList.get(i).getType());
... много кода для перестройки, некоторые настройки графика, графический интерфейс и т. Д. Внутри initGui () мой mxGraphComponent инициализируется
graphComponent = new mxGraphComponent(graph);
Поскольку визуализация графика толькоодна часть приложения и другие данные существуют в фоновом режиме, при этом сохраняются все значения данных, включая положения для вершин и т. д. Поэтому при загрузке файла сохранения создается новое приложение с нуля, просто добавляя все сохраненные значения данных шаг за шагом.шаг.Когда я закрываю все Java-приложение, запускаю его снова и загружаю сохраненный файл, проблем нет вообще.Проблема возникает при загрузке сохраненного файла, когда приложение все еще работает, например,
menuItem = new JMenuItem("Open...",
new ImageIcon("images/middle.gif"));
menuItem.addActionListener(new ActionListener() {
@java.lang.Override
public void actionPerformed(ActionEvent e) {
LoadAndSaveManager manager = new LoadAndSaveManager();
try {
Object o = manager.load(new FileChooser(0).getSelectedFile().getAbsolutePath());
SaveData saveData =(SaveData) o;
Editor editorNew = new Editor(saveData);
new MenuBar(editorNew);
editorNew.setVisible(true);
editor.dispose();
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
menu.add(menuItem);
Моя панель меню довольно проста и получает параметр editor als.Поскольку создается новый редактор, который создает новый mxGraph, а также новый mxGraphComponent и, наконец, удаляет старый редактор, не должно быть никаких помех ... по крайней мере, насколько я знаю.Однако, несмотря на наличие нового экземпляра Editor, который имеет свои собственные новые Graph и GraphComponent, старый все равно каким-то образом используется.Как показано на примере изображения ниже.
Это будет сохранено, и приложение будет полностью закрыто.Два узла и ссылка для сохранения:
При запуске приложения и загрузке сохраненных данных все в порядке.
Далее яначать новый и добавить, например, три узла и две ссылки.Три узла и две ссылки:
Теперь я загружаю ранее сохраненные данные.Я ожидаю, что окно закроется и появится новое с данными prevois.Это не вариант.Данные загружаются, но старый график все еще как-то активен, и все узлы и ссылки находятся на графике.Смешанные данные:
Если бы это была единственная проблема, я мог бы просто очистить график и добавить все «загрузочные данные» впоследствии, однако каким-то образомgraphComponent, похоже, тоже не работает.При перетаскивании узлов ссылки иногда нарушаются.Нарушенные ссылки:
Из моих наблюдений до сих пор это, кажется, исправляется при выборе области (я думаю, что это заставляет graphComponent обновить ()Выбор:
К сожалению, размещение всего кода не так уж и много, поэтому я опубликовал код, который, как мне кажется, может иметь значение для проблемы,Если потребуется дополнительный код, я специально опубликую его позже.
Я не уверен, почему это происходит, и после нескольких часов исследований я как-то врезался в стену, и я не уверен, что я делаю неправильно.Буду очень признателен за советы.
Ниже приведен минимальный пример полного кода проблемы, связанной с проблемой помехи в графе «Компоненты» при объявлении нового.
public class Main {
Editor editor;
public Main() {
editor = new Editor();
new MenuBar(editor);
editor.setVisible(true);
}
public static void main(String args[]) {
new Main();
}}
public class Editor extends JFrame {
mxGraphComponent graphComponent;
protected static mxGraph graph = new mxGraph() {
// Overrides method to disallow edge label editing
public boolean isCellEditable(Object cell) {
if (cell instanceof mxCell) {
mxCell c = (mxCell) cell;
if (c.isEdge()) {
return false;
} else {
return false;
}
}
return false;
}
// Overrides method to disallow edge selection
public boolean isCellSelectable(Object cell)
{
if (model.isEdge(cell))
{
return false;
}
return super.isCellSelectable(cell);
}
// Overrides method to provide a cell label in the display
public String convertValueToString(Object cell) {
if (cell instanceof mxCell) {
Object value = ((mxCell) cell).getValue();
if (value instanceof Element) {
Element elt = (Element) value;
// String tag = elt.getTagName();
String tag = elt.getAttribute("name");
return tag;
}
}
return super.convertValueToString(cell);
}
public String getToolTipForCell(Object cell){
return "Double Click to Edit";
}
};
public Editor() {
initGUI();
initGraphSettings();
}
public Editor(ArrayList<SaveDataElement> saveData) {
initGUI();
initGraphSettings();
//Load data
addToGraph(saveData);
}
public void initGUI(){
setExtendedState(JFrame.MAXIMIZED_BOTH);
setSize(new Dimension(1200, 900));
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
graphComponent = new mxGraphComponent(graph);
JPanel graphPanel = new JPanel(new BorderLayout());
graphPanel.add(graphComponent);
add(graphPanel);
}
public void initGraphSettings(){
Map<String, Object> style = graph.getStylesheet().getDefaultEdgeStyle();
style.put(mxConstants.STYLE_ALIGN, true);
style.put(mxConstants.STYLE_EDGE, mxConstants.EDGESTYLE_TOPTOBOTTOM);
graph.setCellsCloneable(false);
graphComponent.setConnectable(false);
graphComponent.getViewport().setBackground(Color.WHITE);
new mxRubberband(graphComponent);
}
public mxGraph getGraph(){
return graph;
}
public void addToGraph(ArrayList<SaveDataElement> saveData){
for (int i = 0; i < saveData.size(); i++) {
String name = saveData.get(i).getName();
int vertPosX = saveData.get(i).getPosX();
int vertPosY = saveData.get(i).getPosY();
new AddGraphNode("node", name, "rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;", vertPosX, vertPosY);
}
Object[] cells = graph.getChildVertices(graph.getDefaultParent());
Object startCell = null;
Object endCell = null;
for (int i = 0; i < saveData.size(); i++){
for (int j = 0; j < cells.length; j++){
if (((mxCell)cells[j]).getAttribute("name").equals(saveData.get(i).getName()))
startCell = cells[j];
for (int k = 0; k < saveData.get(i).getTargets().size(); k++){
if (((mxCell)cells[j]).getAttribute("name").equals(saveData.get(i).getTargets().get(k))){
endCell = cells[j];
new AddGraphLink(startCell, endCell,"Link", "endArrow=classic;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;verticalLabelPosition=bottom'");
}
}
}
}
}}
public class MenuBar extends JMenuBar {
MenuBar(Editor editor){
JMenuBar menuBar = new JMenuBar();
JMenuItem menuItem;
JMenu menu = new JMenu("File");
menuBar.add(menu);
menuItem = new JMenuItem("Add");
menuItem.addActionListener(new ActionListener() {
@java.lang.Override
public void actionPerformed(ActionEvent e) {
//Setting up some data to create nodes and links
ArrayList<SaveDataElement> saveData = new ArrayList<SaveDataElement>();
ArrayList<String> targetsForTestX = new ArrayList<String>();
targetsForTestX.add("Test Y");
targetsForTestX.add("Test Z");
saveData.add(new SaveDataElement("Test X", 200, 300, targetsForTestX));
ArrayList<String> targetsForTestY = new ArrayList<String>();
saveData.add(new SaveDataElement("Test Y", 300, 420, targetsForTestY));
ArrayList<String> targetsForTestZ = new ArrayList<String>();
saveData.add(new SaveDataElement("Test Z", 100, 420, targetsForTestZ));
editor.addToGraph(saveData);
}
});
menu.add(menuItem);
menuItem = new JMenuItem("Load 1");
menuItem.addActionListener(new ActionListener() {
@java.lang.Override
public void actionPerformed(ActionEvent e) {
//Setting up some data to create nodes and links
ArrayList<SaveDataElement> saveData = new ArrayList<SaveDataElement>();
ArrayList<String> targetsForTest1 = new ArrayList<String>();
targetsForTest1.add("Test 2");
saveData.add(new SaveDataElement("Test 1", 40, 40, targetsForTest1));
ArrayList<String> targetsForTest2 = new ArrayList<String>();
saveData.add(new SaveDataElement("Test 2", 200, 40, targetsForTest2));
Editor editorNew = new Editor(saveData);
new MenuBar(editorNew);
editorNew.setVisible(true);
editor.dispose();
}
});
menu.add(menuItem);
editor.setJMenuBar(menuBar);
}}
public class SaveDataElement {
String name;
int posX, posY;
ArrayList<String> targets;
public SaveDataElement(String name, int posX, int posY, ArrayList<String> targets){
this.name = name;
this.posX = posX;
this.posY = posY;
this.targets = targets;
}
public String getName() {
return name;
}
public int getPosX() {
return posX;
}
public int getPosY() {
return posY;
}
public ArrayList<String> getTargets() {
return targets;
}}
public class AddGraphNode extends Editor {
public AddGraphNode(String tag, String name, String style, int vertPosX, int vertPoxY){
this.getGraph().getModel().beginUpdate();
Object parent = this.getGraph().getDefaultParent();
Document doc = mxDomUtils.createDocument();
Element entity = doc.createElement(tag);
entity.setAttribute("name", name);
try
{
Object v1 = this.getGraph().insertVertex(parent, "1",entity, vertPosX, vertPoxY, (int)(name.length()*8) ,
40, style);
}
finally
{
this.getGraph().getModel().endUpdate();
}
}}
public class AddGraphLink extends Editor{
public AddGraphLink(Object v1, Object v2, String relation, String style){
this.getGraph().getModel().beginUpdate();
Object parent = this.getGraph().getDefaultParent();
try
{
this.getGraph().insertEdge(parent, null, relation, v1, v2,style);
}
finally
{
this.getGraph().getModel().endUpdate();
}
}}
При использовании элемента меню добавления некоторые узлы и ссылки добавляются на график, а с помощью пункта меню загрузки 1 создается новый редактор (созданиеновый граф и graphComponent).Однако добавленные узлы и ссылки все еще присутствуют в новом компоненте.
Что касается визуально битых ссылок, о которых я упоминал выше, этого не происходит ... Я буду исследовать это дальше.Несмотря на это, это также может быть связано с проблемой graphComponent.