Community
Participate
Working Groups
GridLayout is not following the computeSize API in that it should not be subtracting the border or trim size from the control. The API for computeSize says that the width hint is the proprosed width for the control (not it's client area). So the control should already subtract it's own border size within computeSize. It makes more sense to account for the border in the control, than to have SWT layout in existence make this correction. But more importantly, if the child is a Scrollable, GridLayout is calling computeTrim on the scrollable, and removing the scrollbar width from the available width. How does it know that the scrollbar will be displayed? You don't know this, and in my case the scrollbar isn't displayed because that is the whole point of asking the child how much space it wants, i.e. so that scrollbar don't need to be displayed. In fact, the Scrollable may never display its native scrollbars for any purpose, so removing that amount from the available width is bogus.
correction: than to have *every* SWT layout in existence make this correction BTW, this seems to be new 3.1 behavior
The wHint and hHint in Control.computeSize actually do refer to the size of the content area (i.e. the clientArea). The doc says: "The <em>preferred size</em> of a control is the size that it would best be displayed at. The width hint and height hint arguments allow the caller to ask a control questions such as "Given a particular width, how high does the control need to be to show all of the contents?" To indicate that the caller does not wish to constrain a particular dimension, the constant <code>SWT.DEFAULT</code> is passed for the hint. " If you call computeSize with some values other than SWT.DEFAULT, the trim is always added on to the value that is returned (computeTrim is called with the wHint and/or hHint). For example, run the following code: TabFolder folder = new TabFolder(shell, SWT.BORDER); TabItem item = new TabItem(folder, SWT.NONE); item.setText("hello"); System.out.println("computeSize (100, 100) = "+folder.computeSize(100, 100)); On Windows I get: computeSize (100, 100) = Point {112, 130} When GridLayout and FormLayout subtract off the trim from the widget it is because the next call to computeSize is going to add the trim back on and we do not want to account for the trim twice. Steve and I have been discussing a new API for computeSize that would allow you to specify whether the trim should be added or not but this has never been finalized and released.
I do agree tha calling computeTrim with (0, 0, 0, 0) does not allow the underlying control to determine whether or not scrollbars will be shown. However, it is currently the best we can do until we add new API for computeSize. If we try to call computeTrim with values closer to the actual to the correct values, you end up dancing around the edge of where scrollbars are required and where they are not.
Exactly, "given a particular width". But that's the inconsistency, you're actually going to give the control MORE width, and your example shows that. 112 is not 100. That answer wouldn't even be useful if I am trying to determine the height needed for a paragraph that should be wrapped to width == 100. calling computeSize(100, 100) for that type of info. is pointless since you could simply call computeTrim(0,0,100,100) and get the same result. computeSize API becomes useful when you allow the control to grow in one or both directions. So, if I say width is constrained, but height is not, why should the layout manager subtract the vertical scrollbar, when vertical dimension is unbounded meaning that a smart widget would hide the scrollbar. Here is what we are trying to do. Calculate how much height is needed to display a wrapped paragraph, given the available width of the parent composite. Currently our paragraph is returning the wrong answer (because it received the wrong hint) which can result in an unneeded line of text at the bottom. Snippets speak louder than words: public static void main(String[] args) { Display d = Display.getDefault(); final Shell shell = new Shell(d); shell.setLayout(new GridLayout()); StyledText text = new StyledText(shell, SWT.MULTI | SWT.WRAP | SWT.H_SCROLL | SWT.READ_ONLY); text.setText("This is a oijeoi aeif jaoiewjf oaiew jfoaiew" + "apijewpfk apoewkf paokwe pfokawpehfaowephf hawoiejf oaweijf paowkefp aoewkfpa " + "pawkfe paoewkf paowekf pawokefoaiwjefo iajewoifja oewijf poerk pgaokew faewfpokew f" + "f oaewkfp aewpofk apwejfoiuajweo foiwajef poawkefpawkje pfoakewpf aewpfkpaowke fpawf" + "gfpowaegpawepmulti-line label."); GridData data = new GridData(GridData.FILL_HORIZONTAL); data.widthHint = 170; data.heightHint = - 1; text.setLayoutData(data); data = new GridData(GridData.FILL_HORIZONTAL); data.widthHint = 170; data.heightHint = - 1; // label.setLayoutData(data); shell.open(); shell.setSize(600,500); while (!shell.isDisposed()) while (!d.readAndDispatch()) d.sleep(); }
I do not understand what your example is trying to show. I have changed the example as shown below to demonstrate what I think you mean: public static void main(String[] args) { String string = "This is a oijeoi aeif jaoiewjf oaiew jfoaiew" + "apijewpfk apoewkf paokwe pfokawpehfaowephf hawoiejf oaweijf paowkefp aoewkfpa " + "pawkfe paoewkf paowekf pawokefoaiwjefo iajewoifja oewijf poerk pgaokew faewfpokew f" + "f oaewkfp aewpofk apwejfoiuajweo foiwajef poawkefpawkje pfoakewpf aewpfkpaowke fpawf" + "gfpowaegpawepmulti-line label."; Display display = new Display (); final Shell shell = new Shell(display); shell.setLayout(new GridLayout(3, false)); StyledText text = new StyledText(shell, SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.H_SCROLL | SWT.READ_ONLY); text.setText(string); GridData data = new GridData(SWT.FILL, SWT.TOP, false, false); data.widthHint = 170; text.setLayoutData(data); System.out.println("Text = "+text.computeSize(170, -1)); Label label = new Label(shell, SWT.BORDER | SWT.WRAP); label.setText(string); data = new GridData(SWT.FILL, SWT.TOP, false, false); data.widthHint = 170; label.setLayoutData(data); System.out.println("Label = "+label.computeSize(170, -1)); shell.pack(); shell.open(); while (!shell.isDisposed ()) { if (!display.readAndDispatch ()) display.sleep (); } display.dispose (); } I think you are saying that the StyledText widget should have the same height as the Label widget but it does not. You have created a wrapping StyledText widget with a horizontal scrollbar. That is quite strange since the horizontal scrollbar will never be needed because the text wraps. A vertical scrollbar would make more sense. I think if the StyledTextwidget is created with the style SWT.WRAP, then the SWT.H_SCROLL style should be ignored. That is what the Text widget does.
Fixed StyledText in HEAD to ignore H_SCROLL when WRAP is added.
I didn't realize I was showing horizontal instead of vertical. Using a vertical has some issues too, but not the same problem I have. I thought I was using vertical, and that ST was hiding the vertical scrollbar, which is what my paragraph control does.
Try imagining a StyledText control using the V_SCROLL style, but when the scrollbar was disabled, it was hidden instead of sitting there disabled. Once the hiding occurs, there is more width available, and the paragraph might require one fewer line to be displayed. Meaning there is wasted space. It is also possible to subclass Canvas, use the H_SCROLL or V_SCROLL style because you are forced to do so to receive mousewheel events, and never display the native scrollbars. So being an instanceof scrollable doesn't mean that gridlayout should subtract the trim width/height
We should just close this as WONTFIX. Even if Randy is right, we couldn't change the values that computeTrim() and computeSize() return without breaking the universe. Veronika?
I think we need to revisit the idea of having something like: Control.computeSize(int wHint, int hHint, boolean changed, boolean addTrim). Where addTrim is true if the trim should be added to the value of wHint and hHint. If addTrim is false, wHint and hHint include the trim already. This way, controls could implement a computeSize that knows about adding trim only if required and we can stop subtracting off the result of computeTrim before calling computeSize.
But there is no API currently to get the trim you need. My canvas is not going to display its vertical scrollbar if you give it the height it requested. Why not just treat a Control as a black box, and not try to guess about how it works with respect to trim?
The current implementations of Control.computeSize in SWT already go and add the trim to the wHint and hHint. We can not change this because this would change the behaviour which has existed since the beginning of SWT. Therefore, we must add new API to compute the size with the width hint and/or height hint already including the trim amount. Please note that for many composites, adding the trim is really quite useful - take a TabFolder for example. If you want to stick a table of a certain size in a TabFolder and you have no idea what the size of the tabs etc are then you want computeSize to add the trim on for you. This is the case that computeSize was originally intended to solve. However, now we have cases where we know the total width of a widget (including trim if required)and we want computeSize to just tell us the height. We currently have no API to do this.
But, couldn't you just take the size of the table, and go to the tab folder and say computeTrim(tablebounds)? Anyway, no existing behavior can change. So, I guess our Canvas will simply have to add back in the trim width and height, and then just forget that it was ever subtracted.
You canvas should do whatever the rest of the widgets in SWT do for now.
Regarding comment #13 - this assumes you know how that TabFolder lays out its children. In fact, it is not as simple as taking the size of the table since the computeSize(-1, -1) of TabFolder is based on the size of the largest child.
I'm no stranger to the layout problem. From my experience, it's best to treat the child as an unknown, and just pass the hints in. This avoids 2 things. First, you don't make the wrong assumptions about the child. Second, you don't duplicate code in multiple layouts (i.e. Form and Grid) which belonged in the Control. Creating a new method which subtracts the trim and calls the old method would solve my problem and remove the duplicate code from current SWT layouts. But I don't understand the need for the proposed isChanged or addTrim parameters.
references for "computeSize(int, int)" in a subset of Eclipse SDK show lots of matches. References for "computeSize(int, int, boolean") show some more matches. Most callers are not checking if the control is an instance of Scrollable, and subtracting the trim width from the wHint. Examples include: PageBookLayout PopupList ScrolledCompositeLayout EnhancedFillLayout SashFormLayout The simple fact that computeSize is on Control, while computeTrim is on Scrollable, is a clear indicator that one should not have to subtract the trim, as it requires an instanceof and cast. Dupe of bug 46112?
Not really, does every control have trim? I agree that we could move the concept up and say that every control has trim but it can be zero.
(In reply to comment #18) > Not really, does every control have trim? I agree that we could move the > concept up and say that every control has trim but it can be zero. What I am saying is that for me to call control.computeBounds(wHint), I must first do: if (control instanceof Scrollable) wHint -= ((Scrollable)control).computeTrim(0,0,0,0).width; which is ugly. My vote is to fix, or to deprecate and add new API, since many clients are misuing. *** This bug has been marked as a duplicate of 46112 ***
I agree. The (ugly) pattern we are using is temporary code. The real fix to happen after 3.1.