Swing layman pagination

2019-03-02 00:42发布

问题:

Before I start, similar question (of mine) exists, I'd like that one to be deleted since I didn't explain my point well there, but not this one. Thank you.

First of all, I have no code, this is only a concept that I can't figure out. But it's interesting (at least to me).

You all know how MSWord works. You write stuff. Then, when you fill a page it will create a new page and start writing on that page. If you paste some more text to the first page, everything will be pushed down. If you delete a large chunk of text on a page, it will suck up some of the text on the previous page. If you're dealing with e.g. pictures and you have one on top of a page, reducing it's size my cause it to get sucked up to the previous page, if there is enough room for the reduced version of the picture.

Now that you're thinking this way, I want to transfer that concept into Java Swing. Pages are JPanels, and pictures and chunks (or lines) of text are JPanels fitted onto the page JPanel.

I have come up (okay, I lied, I have some code, but it's a mess and it doesn't work anyway) with a method using a Filler, which doesn't work in all cases. If you want to know why, read between the two lines, otherwise just skip it.


So, the structure itself is easy to replicate, but maintaining it is a pain in the neck. You see, there are two main types of events that can occur:

a) height of the page content has increased
b) height of the page content has decreased

By using a Filler as the last component of a page, and having a componentAdapter (componentResized) attached to it, you can monitor those changes.

These changes can further be dividet into:

a) element is added/removed to/from page
b) height of the element has increased/decreased 

Taking those events into consideration many things can happen. Skipping the simple cases, look at this example:

Page 1:
{element 1
blabla
blabla}
{element 2
blabla}
{element 3}
{element 4
blabla
blabla
blabla
blabla}
{free space
---
---
---}

/

Page 2:
{element 1
blabla
blabla
blabla
blabla}
{element 2
blabla
blabla
blabla
blabla}
{element 3}
{element 4
blabla
blabla
blabla}

/

Page 3:
{element 1}
{element 2}
{element 3}
{element 4}
{element 5}
{free space
---
---
---
---
---
---
---
---
---}

Each page has a height of 15 rows. Look now what happens if you reduce the height of the element 1 of the second page by one row. It will become 4 rows high, making it fit to the previous page, being sucked up. That will create 5(1 deleted row + 4 sucked up rows) rows worth of free space on the second page. That will suck up all the five elements on the third page and leave the third page blank (which should now be deleted).

The reason this wouldn't work is because upon deletion, a listener is triggered for the second page and it has to both push the top element up, and suck up the elements from the previous page. Since it's all done in a listener, I have to wait for it to execute in order to register visual change in my program. Since it has to change two thing on a page, it comes to somekind of listener chaos. Page height is reduced twice but is registered only once and in the end I can fully move only thr top part or the bottom part, or a single component on each side. This isn't really a good explenation, but if you understand how swing works, you should be able to connect the dots yourself.

As I mentioned before, I have written the code for that, but it's long and hard to follow, and I can post it here, if anyone shows the desire to see it. And I'm talking about SSCCE itself. It really can't be shortened into couple of 10s of rows of code.


What I would want is to skip writting an algorithm that would maintain the structure of the "document" and move all the elements around, since it's a really complicated thing to do, taking all the numerous cases.

What I want is an alternative and I'm asking you if you have any ideas. One thing that came to my mind is having a component similar to JPanel. It would have fixed height-parts that can be populated with other components, and between them fixed height-parts that are unpopulable(?) or "solid".

Way it would work would be that everytime you add something to populable(?) parts, they would be automatically rearanged. If something doesn't fit to the current populable part, it's just moved to the next one (similar to how verticall box layout works, adding one thing to a spot pushes all the others down), but skiping the solid part.

Since I would also have to be able to tell in which populable part a certain component is, I don't know if creating a such structure is possible in Java swing.

Well, any advice is welcome, external libaries included.

Just keep in mind that this whole document is document with pages that would be placed one after another in a JScrollPane's viewport, and that is the only limit to what it should look like.

回答1:

Let the layout do the work: add() instances of JPanel, each having its own preferred size based on content, to a Box having a vertical layout. Put the Box in a JScrollPane, optionally implementing Scrolable. Use the scroll pane's row and column headers as needed; JTable is an example. You can remove() a panel from the Box, revalidate() and repaint() as required.

Addendum: The initial answer addressed only the view aspect of the problem. It may help to separate the model and view more rigorously, as the text components do; remove content from the model and signal the view to update itself accordingly. To achieve this, several common approaches to implementing the observer pattern are mentioned here.