所以我的程序中有一组 JPanel、页面(固定大小)。它们中的每一个都包含一个 JTextArea 数组。
用户可以使用键盘添加更多的 JTextArea,并且可以在添加或删除文本时自动调整它们的大小(它们的本机行为,对)。
我需要实现(在某种程度上我确实做到了)是一个代码,它将处理这些事件并将不再适合页面的任何 JTextArea 移动到下一个页面上,并且当页面上释放一些空间时,尝试如果有足够的空间,将内容从下一页移回该可用空间。总而言之,基本页面管理的东西。
第一个问题是这些变化可能足够大,以至于需要移动几个元素。
我所做的是在每个页面的末尾添加一个填充对象,并在其上附加一个侦听器,该侦听器会在每次调整填充大小时触发,并且在发生上述任何事件时都会调整大小。
侦听器代码自然地移动对象。
现在,如果我把所有东西都这样丢掉,我会搞得一团糟。每当满足上述条件之一时,听众就会在一个大的连锁反应中被触发。
现在,这就是我到目前为止想出的(此代码仅适用于缩小或删除元素时,添加代码足够相似,无需打扰您)。这在侦听器的 componentResized() 方法中调用:
public void movingElements()
{
//gets the new filler height to compare
int newFillerHeight = getFiller().getHeight();
//chapter contains an array of pages I need to deal with here
Chapter chapter = getChapter();
//element removed/shrunk
//compares the oldFillerHeight which contains the height of the filler
//prior to this particular resizing
else if (newFillerHeight >= oldFillerHeight)
{
//fetches the next and previous page of this page (getPage()
//returns page we are dealing with)
Page previousPage = chapter.getPreviousPage(getPage());
Page nextPage = chapter.getNextPage(getPage());
//here is where it gets tricky
//I didn't want to check if first (few) element(s) can be
//moved to previous page (which can happen if the first, large
//element followed by several small ones is removed) (CHECK A) AND
//if any elements on the next page can be moved to this one
//(CHECK B). What I did instead was to always do the CHECK A.
//if this is the first page of the chapter, I cannot perform the
//CHECK A
if (previousPage == null)
{
//I have to invoke this method on the next page, if it
//exists. If it doesn't, then this is the only page of
//the chapter and I have nothing to do here.
if (nextPage != null)
{
//this is explained bellow this method
nextPage.dummy.setVisible(true);
}
}
//if previous page exists, we preform CHECK A
else
{
Element mover = getElement(1);
//I have to check if the first element on this page fits
//onto the free space of the previous one
//-2 is required to prevent infinite loops
if (mover.getHeight() < previousPage.getFiller().getHeight()-2)
{
//I move the element
removeElement(mover);
previousPage.addElement(mover, previousPage.getElementCount()+1);
//This is a flag that tells that an object was
//moved, you'll se why I need it soon enough
chapter.setMoved(true);
}
//If I can't move the object, I have move onto the next
//page (if it exists) and repeat the process. I also
//check for isMoved flag because maybe nothing was moved
//on the previous page and there is no need to keep the
//this chain of execution going
else if ((nextPage != null) && (chapter.isMoved()))
{
//sets isMoved flag to false so the above code
//would work
chapter.setMoved(false);
nextPage.dummy.setVisible(true);
}
}
}
//saves the new filer height for further use
oldFillerHeight = newFillerHeight;
}
注意:Element 是一个扩展 JPanel 并在其中包含 JTextArea 的类,它决定了它的高度。
这是假人的全部内容:
dummy = new JPanel();
dummy.setVisible(false);
dummy.addComponentListener(new ComponentAdapter()
{
@Override
public void componentShown(ComponentEvent arg0)
{
dummy.setVisible(false);
movingElements();
}
});
这样做是为了确保在下次调用movingElements() 时重新绘制所有内容。如果我直接从其本身调用它,它会在填充物更新它的高度之前消失,把事情搞砸。
我不知道这是否是正确的做法,它看起来很简单,但看起来很复杂。
但是现在我需要以某种方式确保在它的执行链完成之前永远不会从侦听器调用此方法。我也不需要用户做任何事情来使其中两个并行运行,所以我想完全阻止用户,直到链完成。这一切都完成得非常快,但仍然......
那么,这是正确的做法,还是我应该采取其他方式?如何确保当时只有一条链在运行?
编辑:
抱歉代码格式,标签在编辑框中看起来非常好,但在显示中都搞砸了......
编辑2:
我解决了它,这就是我所做的:
填充代码:
filler.addComponentListener(new ComponentAdapter()
{
@Override
public void componentResized(ComponentEvent arg0)
{
if (!getChapter().isChaining())
{
getChapter().setChaining(true);
movingElements();
}
oldFillerHeight = getFiller().getHeight();
}
});
虚拟代码:
dummy.addComponentListener(new ComponentAdapter()
{
@Override
public void componentShown(ComponentEvent arg0)
{
dummy.setVisible(false);
movingElements();
}
});
移动元素()方法:
public void movingElements()
{
int newFillerHeight = getFiller().getHeight();
Document document = getDocument();
Chapter chapter = getChapter();
//element added/enlarged
if (newFillerHeight == 0)
{
Page nextPage = chapter.getNextPage(getPage());
if (nextPage == null)
{
nextPage = new Page();
chapter.addPage(nextPage, chapter.getPageIndex(getPage())+1);
}
Element mover = getPage().getElement(getPage().getElementCount());
removeElement(mover);
nextPage.addElement(mover, 1);
getPage().dummy.setVisible(true);
}
//element removed/shrunk
else if (newFillerHeight >= oldFillerHeight)
{
Page previousPage = chapter.getPreviousPage(getPage());
Page nextPage = chapter.getNextPage(getPage());
if (previousPage == null)
{
if (nextPage != null)
{
nextPage.dummy.setVisible(true);
}
else
{
//chain end
chapter.setChaining(false);
}
}
else
{
Element mover = getElement(1);
if (mover.getHeight() < previousPage.getFiller().getHeight()-2) //-2 is required to prevent infinite loops
{
removeElement(mover);
previousPage.addElement(mover, previousPage.getElementCount()+1);
chapter.setMoved(true);
getPage().dummy.setVisible(true);
}
else if ((nextPage != null) && (chapter.isMoved()))
{
nextPage.dummy.setVisible(true);
}
else
{
//chain end
chapter.setChaining(false);
}
}
}
else
{
//chain end
chapter.setChaining(false);
}
}
我将此添加到所有页面的所有者章节:
private AtomicBoolean chaining= new AtomicBoolean(false);
public boolean isChaining()
{
return chaining.get();
}
public void setChaining(boolean chaining)
{
this.chaining.set(chaining);
}
我可能会在这两种方法中添加键盘输入阻止程序和解除阻止程序。