【问题标题】:Page managment in swing页面管理在摇摆
【发布时间】:2013-09-10 23:10:52
【问题描述】:

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

用户可以使用键盘添加更多的 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() 时重新绘制所有内容。如果我直接从它的自身调用它,它会在填充器更新它的高度之前消失,把事情搞砸。

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

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

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

编辑:

对不起,代码格式,制表符在编辑框中看起来很不错,但在显示中却一团糟......

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

我可能会在这两种方法中添加键盘输入拦截器和解锁器。

【问题讨论】:

  • 您是否考虑过 JPanel 与 JTextArea 或 JTable 中的 JTextArea 只有一列,有或没有 JTable Header
  • 我需要 GUI 看起来像 MSWord 文档。至少就页面而言。如果您要求 Element 对象,它可以有多个版本,但唯一重要的是它包含一个指示其高度的 JTextArea。我没有使用任何与它们相关的任何 JTables...
  • 如果 JTextArea 比页面本身大怎么办?
  • 我创建了一个自定义 DocumentFilter 来防止用户输入足够多的字符来...
  • 我宁愿做一些独立于 UI 事件的事情,比如每次有一个 height_change/insert/remove 调用一个解决这个问题的方法:“给定一个整数列表(JTextAreas 高度)把它们在单元格(页面)中,按照给定的顺序,尽可能多地填充每个单元格,而不超过最大单元格容量(页面高度)”。这是微不足道的。然后,如果您移动了一些东西,请更新 UI。

标签: java swing concurrency


【解决方案1】:

http://java-sl.com/Pagination_In_JEditorPane.html 可能会导致分页。

对于您的情况(JTextArea 中没有格式的文本)我将只使用一个 JTextArea 并更改 ViewWrappedPlainView 或只是 PlainView)来呈现页面。

【讨论】:

  • 我已经读过了。我不适合我,我需要一堆 JTextAreas 来让用户更清楚地把什么放在哪里。就像他在填写一个动态表格。不过还是谢谢你的建议……
  • 我曾经使用过这样的东西(多个相关的 JComponents - 链接的文本框),这确实是个问题。我建议只使用一个模型并在 one 视图中使用所有视觉效果来表示它。
猜你喜欢
  • 2013-01-10
  • 2012-10-16
  • 2012-11-20
  • 2013-04-29
  • 2015-05-09
  • 1970-01-01
  • 2019-11-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多