- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
嗨,我正在使用 JGraphX 构建某种基于 Java swing 的图形编辑器应用程序。一般情况下,该应用程序运行良好,并且在正常情况下符合预期情况。一般来说,我有一个名为 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());
...大量用于重建的代码、一些图形设置、GUI 等。在 initGui() 内部我的 mxGraphComponent 已初始化
graphComponent = new mxGraphComponent(graph);
由于图形可视化只是应用程序的一部分,其他数据存在于后台,而保存时所有数据值都被存储,包括顶点的位置等。因此,在加载保存文件时,从头开始构建一个新的应用程序,只需逐步添加所有保存的数据值。当我关闭整个java应用程序,再次启动它并加载我保存的文件时,根本没有问题。当应用程序仍在运行时加载已保存的文件时会出现问题,例如 e.克。
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);
我的菜单栏非常基本,可以获取编辑器参数。由于创建了一个新的编辑器,它创建了一个新的 mxGraph 以及一个新的 mxGraphComponent 并最终处理了旧的编辑器,因此应该没有干扰......至少据我所知。然而,尽管有一个新的 Editor 实例,它有自己的新 Graph 和 GraphComponent,但旧的仍然以某种方式使用。如下面的示例图片所示。
这将被保存并完全关闭应用程序。两个节点和一个保存链接:
启动应用程序并加载保存的数据时没有任何错误。
接下来,我开始一个新节点并添加例如三个节点和两个链接。三个节点和两个链接:
现在我加载之前保存的数据。我希望窗口关闭,并弹出一个包含先前数据的新窗口。不是这种情况。数据已加载,但旧图似乎仍然处于 Activity 状态,并且所有节点和链接都在图上。混合数据:
如果这是唯一的问题,我可以简单地清除图表并随后添加所有“加载数据”,但是不知何故,graphComponent 似乎也被破坏了。拖动节点时,链接有时会中断。中断的链接:
根据我到目前为止的观察,选择一个区域时这似乎可以自行修复(我认为这会强制 graphComponent 刷新())选择:
不幸的是,发布整个代码并不是一个好的选择,所以我发布了一些我认为可能对问题很重要的代码。如果需要更多代码,我会在之后专门发布。
我不知道为什么会发生这种情况,经过几个小时的研究,我不知怎的碰壁了,我不知道我做错了什么。我真的很感激一些建议。
<小时/>这是一个最小的完整代码示例,说明了声明新组件时有关 graphComponents 干扰问题的问题。
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 问题有关。
最佳答案
我在您的代码中发现了 3 个主要问题:
protected static mxGraph graph = new mxGraph() {
public class AddGraphLink extends Editor {
class AddGraphNode extends Editor {
通过使图形字段静态,对一个变量所做的更改将在所有变量中感受到,这可能是造成所谓的“工件”的原因。您之所以觉得必须将字段设为静态,是因为上面的两个类继承自 Editor(同样不恰当)。解决方案很明显:
// protected static mxGraph graph = new mxGraph() { //!! **** NO ****
private mxGraph graph = new mxGraph() { //!! **** YES ****
.....
.....
public class AddGraphNode {
public AddGraphNode(Editor editor, String tag, String name, String style, int vertPosX, int vertPoxY) {
// **** note use of the editor parameter below ****
editor.getGraph().getModel().beginUpdate();
Object parent = editor.getGraph().getDefaultParent();
Document doc = mxDomUtils.createDocument();
Element entity = doc.createElement(tag);
entity.setAttribute("name", name);
try {
// **** same here ****
Object v1 = editor.getGraph().insertVertex(parent, "1", entity, vertPosX, vertPoxY,
(int) (name.length() * 8), 40, style);
} finally {
// **** and the same here ****
editor.getGraph().getModel().endUpdate();
}
}
}
您可以通过传入 this
参数在编辑器中创建此实例:
new AddGraphNode2(this, "node", name,
"rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;",
vertPosX, vertPosY);
您将对 AddGraphLink 类进行类似的更改。
<小时/>旁注,请查看The Use of Multiple JFrames, Good/Bad Practice?了解为什么交换 JFrame 不是最好的程序设计,以及如何更改代码以改善其结构和用户体验。
关于java - JGraphX 图形/图形组件的新初始化无法按预期工作并导致伪影,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53673248/
如标题所示,我正在寻找有关伪/冒号 header 字段用途的一些信息,即我想知道为什么我们有第二种类型的 header 字段... 另外 - 我知道在 http2 中使用伪/冒号 header 字段代
(伪)多线程:借助外力 利用WEB服务器本身的多线程来处理,从WEB服务器多次调用我们需要实现多线程的程序。 QUOTE: 我们知道PHP本身是不支持多线程的, 但是我们的WEB服务器是支持多线程的
您如何在 HDL (verilog) 中实现硬件随机数生成器? 需要考虑哪些选项? 这个问题是在self-answer之后格式。鼓励添加答案和更新。 最佳答案 正如摩根的回答中所指出的,这只会产生一个
我写了这个CSS: div { width: 500px; height:150px; margin-left:150px; background: lightblue; } div:
这是我要解决的问题:从数据库A读取一个字符串,将该字符串转换为Date对象,将Date对象存储到数据库B中。 例)数据库A:从数据库A读入日期字符串“ 2015-03-08 02:00:00”,转换为
我想创建 std::fscanf() 的 sibling (我知道这是一个 C 函数)。所以,我的界面是这样的: template std::size_t ts_scanf(is, format,
运行 PostgreSQL 7.x(是的,我正在升级) 问题: 如果没有返回数据,我有三到四个字段需要设置。 正在考虑这样的事情 SELECT CASE WHEN default_fie
出于某种原因,我很难在 JS 中为我的游戏执行以下代码: 假设我们要求用户在棋盘上移动一个棋子。他们可以做的位置是位置A、位置B或位置C。每个位置一次只能容纳一件。否则为无效移动。 第一个用户决定
我已经毫无问题地编写了霍夫曼树的代码,但现在我希望在文件和树中添加伪 EOF,以便我知道何时停止从文件中读取。 我完全掌握了伪 EOF 的概念。我还了解到没有 ASCII 值 > 255 的字符。 我
给定一个按钮 ::after 当被触发时,伪 :after 类需要有一个类 search-active 切换,为按钮设置背景颜色 .primary .search:after, .primary
我想让第一行的文本像第二行一样缩进 (50px)。有什么办法吗?非常感谢! body{ counter-reset: h2counter; } h1{ counter-reset: h2counter
:before 或 :after 这样的伪元素是否可以从父元素的不同属性继承值? 在我的例子中,我有一个第三方组件设置其元素运行时的背景颜色...我需要继承该颜色并将其设置为伪元素的边框颜色。 最佳答
在并行循环中请求随机数总是返回相同的伪随机数。我怎样才能避免这种情况? % workers initialization: if matlabpool('size') == 0 matlabp
假设最大IP可以包含每个“点”括号中的最大数量999,即999.999.999.999 是最大的可用值。 我已经在计算器中检查了正则表达式 ([0-9]+.){3}[0-9]。那么,为什么程序抛出运行
我对随机数生成的概念非常陌生,我需要为用c编写的工作创建自己的算法(内置的随机数生成器对我不起作用)。 有人能给我介绍一个很好的主题,这样我就可以理解这个概念了吗?到目前为止,我所发现的一切似乎都是用
假设我有一个数字序列:{n, n+1, n+2, ... n+m} 在不提前存储数字的情况下,我想创建一个函数 f(),给定序列 {1,2,3,...m} 将以随机(或至少伪)的方式吐出原始集合随机)
什么是伪 tcp channel ,如何实现? 最佳答案 伪 TCP 是一种协议(protocol),它实现了 TCP 的一些思想,以通过不可靠的、基于数据包的接口(interface)提供可靠的数据
我正在尝试展开一些嵌套循环,以牺牲内存为代价(可能)获得更好的性能。在我的场景中,我最终会得到一个包含大约 3 亿个元素(元组)的列表,我必须以(或多或少)随机顺序产生这些元素。 在这个数量级上,ra
如何在 PHP 中生成(伪)随机字母数字字符串,例如:'d79jd8c'? 最佳答案 首先创建一个包含所有可能字符的字符串: $characters = 'abcdefghijklmnopqrstu
我有一段代码可以为玩家生成迷你任务。这很简单,要获得两个不同的点(起点和终点),我有一个如下所示的算法: std::vector missions; missions.push_bac
我是一名优秀的程序员,十分优秀!