页面管理在摇摆

时间:2013-09-10 13:02:36

标签: java swing concurrency

所以我的程序中有一系列JPanels,页面(固定大小)。它们中的每一个都包含一个JTextAreas数组。

用户可以使用键盘添加更多JTextAreas,并且可以在添加或删除文本时自动调整它们(原生行为,对吧)。

我需要实现的(我在某种程度上做了)是一个代码,它将处理这些事件并将任何不再适合页面的JTextAreas移动到下一个页面上,并且当一个空间被释放时页面,如果有足够的空间,尝试将内容从下一页移回到该可用空间。总而言之,基本页面管理的东西。

首批捕获量之一是,这些变化可能足够大,需要移动一些元素。

我所做的是在每个页面的末尾添加一个填充对象,并为其附加一个侦听器,每次调整填充程序时都会触发该侦听器,并在发生上述任何事件时调整它。

监听器代码自然地移动对象。

现在,如果我把这样的东西都留下来,我会得到一个大混乱。每当满足上述条件之一时,听众就会在一个大的连锁反应中被触发。

现在,这是我到目前为止所提出的(此代码仅适用于元素缩小或删除时,添加代码足够相似,无需为此烦恼)。 这在侦听器的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()时重新绘制每个内容。如果我直接从它的lef中调用它,它会在填充物更新它的高度之前消失,搞乱了。

我不知道这是否是正确的做法,它看起来最简单,看起来多么复杂。

但是现在我需要以某种方式确保在执行链完成之前永远不会从侦听器调用此方法。我也不需要用户做某事来使其中两个并行运行,所以我想完全阻止用户,直到链完成。这一切都很快完成,但仍然......

那么,这是正确的做法,还是应该采取其他方式? 如何确保当时只有一个链正在运行?

编辑:

很抱歉代码格式化,标签在编辑框中看起来非常不错,但它们都在显示屏上搞砸了......

EDIT2:

我解决了,这就是我所做的:

填充码:

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();
        }           
    });

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);
}

我可能会在这两种方法中添加键盘输入阻止和解除阻塞。

1 个答案:

答案 0 :(得分:1)

http://java-sl.com/Pagination_In_JEditorPane.html可能会因为分页而受到影响。

对于您的情况(JTextArea中没有格式化的文字),我只使用一个JTextArea,并将ViewWrappedPlainViewPlainView)更改为渲染页面。