Java FX TextArea ScrollLeft Precision with Backspace - java

In the TextArea widget of Java FX 2.2, the method getScrollLeft is described in the documentation as returning
The number of pixels by which the content is horizontally scrolled.
More precisely, it accesses the value of the property ScrollLeft which has the above description.
When I slide either the horizontal or vertical scrollbar, this variable is adjusted, as expected. However when I press "backspace" on a line that is longer than the screen width such that the scroll amount decreases, or at the first character of a row, the property is not adjusted even though the scroll position changes.
A hacky way to fix this is to access the scrollbar directly, get how much of it is being scrolled, and calculate the appropriate value based on that information. I'd prefer not to do this.
Is there an accepted way to solve this problem, or am I misusing the scrollbar information?

Related

Table control with sliding row headers in JavaFX

The album view in iTunes has a slick effect where the album title and cover art stay in view at all times. If you slide down the screen they stay pinned to the top of the screen until they bump into the next album, then they slide away.
Notice how the top album is still fully visible even though the user has scrolled down a ways.
What is this control or effect called? I'm coming up with blanks trying to Google for it.
How can I do this in JavaFX? I want to mimic this in my Java-based GUI. Can TableView do this, or maybe some third-party control?
The easiest way to do this is with a ScrollPane. Inside your ScrollPane you define your rows and their layouts (probably each row is an HBox containing an ImageView and a TableView which is set to the height of the ImageView). Then, the TableViews inside your ScrollPane need to let the ScrollPane override their scrolling - that is, their onScroll bubbles up to the ScrollPane.
Then you override the onScroll behavior for your ScrollPane. The algorithm for the scrolling could go like this:
There are two modes.
1) Scrolling IN an album scrolls the TableView in that row. If the scrolling goes beyond the boundaries of the TableView's scrollHeight (the range between 0 and scrollHeight), then the mode switches to scrolling TO an album.
2) Scrolling TO an album scrolls the ScrollPane an amount up to the height of the current row. Scrolling an amount greater than the current row's height moves to the next album and switches the mode back to Scrolling IN that album.
3) Edge Cases: Scrolling within the ScrollPane beyond the boundaries of the ScrollPane's scrollHeight (the range between 0 and scrollHeight) immediately moves to the next album and switches the mode back to Scrolling IN that album.
I'd give a code example, but I've never actually seen anybody try to do this. I just know you CAN do it.
I would recommend you to take a look to the SpreadsheetView in ControlsFX
The SpreadsheetView allow you to fix at the top of the screen any number of line. So you would have the first part of your behavior.
Regarding the fact of bumping into another, it would be more difficult but not impossible with the SpreadsheetView.
Anyway, if you want to implement that behavior in the TableView, you will find very useful tricks in the SpreadsheetView code.
This is how a section title acts as default in a UITableView.
https://developer.apple.com/Library/ios/documentation/UIKit/Reference/UITableView_Class/index.html
This should help you on how to create and use UITableView

Make java scrollbar start in middle of the scrolling content

I have a horizontal scrollbar that controls a large panel (with a very large width, and a very small height, thus an horizontal panel).
I want the start of the scrollbar (when the knob is at max left) NOT to start at the beggining of the panel it is scrolling, but rather in a specific place that I dictate. The same for the end of the scrollbar (when the knob is at max right).
I find that the scrollbar is always bound to the panel it is scrolling, and I can't figure out how to change its behaviour.
EDIT:
As an example, picture a normal web-page: when at the top of the page, the scrollbar knob is also at the top. When at the bottom, the scrollbar knob is at the bottom. I want to define new limits for the content, such that when the scrollbar knob reaches the top or bottom, the page is showing the limit I defined, instead of the real top and bottom.
As shown in How to Use Scroll Panes, you can use the component's scrollRectToVisible() method to scroll to an arbitrary Rectangle. There's an example here.
Addendum: As a Container, a JPanel is fairly fungible even if it has considerable nested content. One reliable way to swap content at a given level is via CardLayout, shown here, here and here.
I solved the problem by using the JScrollbar method setValues(), which allows me to set at the same time the maximum, minimum, value and extent of the scrollbar. By setting the maximum and minimum to the values I want, the scrollbar behaves as I wanted/expected.
The problem was that I was only setting maximum and minimum values (setMaximum, setMinimum), and since there is a strict policy at the model that minimum <= value <= value+extent <= maximum, that estrategy did not work.
Would it be possible to keep the large panel as a backing store and copy the region of interest into a panel which is actually realized in the scrollpane. This way you don't have to fight the behavior of the scrollpane.

Scrolling issues with a TextArea in LWUIT

I have a TextArea in LWUIT that I am having an issue manipulating. I have the following two issues:
Even though I call setIsScrollVisible(true), I do not seem to have a
scrollbar and cannot scroll when the output goes below the visible
area of the container.
How do I tell the TextArea to automatically scroll to the bottom
programmatically?
My code for initializing the TextArea looks like this:
myTextArea = new TextArea(20, Display.getInstance().getDisplayWidth());
myTextArea.setEditable(false);
myTextArea.setEnabled(true);
myTextArea.setIsScrollVisible(true);
myTextArea.setGrowByContent(false);
System.out.println(myTextArea.isScrollableY());
isScrollableY() returns true. Any ideas? Is there something I am missing? There doesn't seem to be anything visible in the API that lets me explicitly enable or disable scrolling. Thanks in advance for any assistance on this.
The width of the text area is in columns NOT pixels as you have in your code.
Setting the scroll to visible won't cause it to appear since LWUIT scrollbars are always "as needed" which means a scrollbar will only appear when necessary, setting this value to false would just hide the scrollbar regardless of necessity.
To have the text area grab the entire width just place it within a box layout Y container/form and the layout manager will stretch it on the X axis.
You can use scrollRectToVisible() to scroll the text area to the bottom or alternatively you can derive text area and use setScrollY(int) with the appropriate value (see the source code of text area for how this is used to scroll the text area.
Try a simple textArea.setFocusable(false). This worked for me.

JXMultiSplitPane going bonkers when I switch tabs

I'm using JXMultiSplitPane (from SwingX 1.6.2) to implement a three-pane horizontal interface. In the center pane is a JTabbedPane with two tabs: one with a JTextArea (in a JScrollPane, of course) used for entering Markdown code and the other a JEditorPane (again, in a scroll pane) for displaying a rendered HTML preview. When the user switches to the preview pane, the text in the editor is processed and displayed in the preview pane.
My problem is that if I enter text in the editor with long lines, and then switch to the preview, the center pane will expand. Sometimes it's just by a little bit, other times it'll take up more room than is actually on the screen. But if I move one of the resize handles manually, everything will snap back in place.
I've found only two ways to deal with this before it happens:
Manually resize one of the panes before entering any text.
Give the center pane a weight of 1 in the MultiSplitLayout model.
I can't use the second one since it will expand the center pane to take up almost the whole window by default.
Is there a way to fix this?
Update
After a little more testing, even technique (2) doesn't keep the size constant; switching between the two tabs changes the size of the center pane slightly.
I now believe that the problem is partly with the tabbed pane. The JTextArea and the JEditorPane do not have the same size and that JTabbedPane is resizing when I switch between them (since I'm resetting the JEditorPane text every time. This wouldn't be a problem except that JXMultiSplitPane will keep automatically resizing the center pane until the user forces a specific size by resizing manually.
So I should be able to fix the issue by making the size of the JTabbedPane fixed, but still able to be resized by the handle bars. Any tips on doing that?
The MultiSplitLayout is .. a LayoutManager, so you have to understand how it works (me too, not overly familiar with it myself :-)
The basic layout happens according to the component's prefSize, the weights are for distributing excess/missing space relative to the pref. By default, the dividers are "floating", that is they are positioned between the components as layouted by the basic mechanism. The moment a user touches a divider, dividers are "not-floating", comp sized to fit in-between the dividers. That's the reason for you not seeing the size-greed after moving the divider once. So one ways out is to
setup the JXMultiSplitPane as usual, add the components and realize the frame
fix the dividers after the manager has done its initial layout
String layout = "(ROW " +
"(LEAF name=selector weight=0.15)" +
"(LEAF name=center weight=0.7)" +
"(LEAF name=list weight=0.15)" +
")";
JXMultiSpitPane pane = new JXMulitSplitPane((MultiSplitLayout.parseModel(layout))
// add components and realize the frame
...
pane.getMultiSplitLayout().setFloatingDividers(false);
Alternatively, give more weight to the weights - force the layoutManager to use them for the layout itself (instead of only for the distribution of excess/missing space). A side-effect is that the prefSize of the comps might be set (by the layout, which is a no-no-never, but who's perfect ;-)
pane.getMulitSplitLayout().setLayoutByWeights(true);
Not sure which way I would prefer or if/how that could be made easier in the multisplit ..

GridBagLayout manager and resizing controls

I'm not sure if GridBagLayoutManager is the only layout manager that does this, but here is my problem. I have 4 controls layed out horizontally in a GridBagLayout. To keep things simple for this example, each control get's an equal 1/4 of the form, and each control resizes with the same ratio as the other controls. The four controls are JTextField's where each text field maps to a column in a record from a ResultSet. Additional controls on the form allow one to navigate through the records.
If I navigate from one record to the next, then the text fields update their text to show the new data. However, the text fields also get automatically resized in proportion to the amount of text they are showing... text fields with a large amount of data expand in size, and text fields with a smaller amount of data get squished. If I run through 10 records in a ResultSet, then the controls are always resizing themselves and it looks quite bizarre to say the least.
What I would like to do is prevent these controls from resizing, unless (and until) the underlying container gets resized. So if I resize the window, then I would like the controls to resize (according to the "weight x" variable in the Layout), but I don't want the controls to resize just because the amount of text they are showing becomes more or less.
Anybody have any ideas here?
For JTextField (as mentioned in the contents) call setColumns(int) to set a preferred size on the text.
For JComboBox, call setPrototypeDisplayValue(Object) which will cause that value to be rendered and the preferred size of the JComboBox will be set based on that value.
In general, you can call setPreferredSize(Dimension) on any component directly to get the same behavior. General if not set the value is calculated based on some defaults on the component. What is happening with JTextField, JComboBox, and most JTextComponent derivatives. is that the preferred size on those components is driven by values the user is capable of changing (the text values, the combobox selection). Whereas with most other component (JButton, JCheckBox, etc) the content size doesn't really change when the user acts on it. Setting the columns and rows and the prototype display value fixes the value used to calculate the preferred size.

Categories

Resources