I've started building a small search engine for an index I created using Lucene. I use the GWT to create the GUI I like but I'm stuck in a problem. I am trying to add some results inside a FlowPanel which is inside the center of a DockLayoutPanel so I can have scrolling the page as I like. My problem is (as I found out ) that in order for scrolling to work ( and not have the browser window cut my results ) is to make every DockLayoutPanel child to not have position:absolute. My problem is that I cannot remove it ( or I don't know how ). When I disable it from chrome inspector scrolling works but when I re-enable it it cuts the flowPanel. Here is the java code :
public static void loadCellTrees(HashMap<Integer,LinkedHashMap<String,String>> searchResults, List<RootCategories> list)
{
VerticalPanel westTrees = new VerticalPanel();
TreeViewModel treeModel = new CellTreeWidget(list);
CellTree tree = new CellTree(treeModel, null);
HTMLBuilder builder = new HTMLBuilder(searchResults);
tree.setStyleName("tree");
tree.setAnimationEnabled(true);
dock.clear();
westTrees.clear();
westTrees.getElement().setAttribute("align", "center");
westTrees.add(tree);
FlowPanel resultsPanel = new FlowPanel();
resultsPanel.setStyleName("resultsPanel");
for(int i=0; i<searchResults.size(); i++)
{
HTML box = builder.toHTML(i);
box.setStyleName("resultBox");
resultsPanel.add(box);
}
dock.addWest(westTrees, 20);
dock.addNorth(RootPanel.get("wrap"),20);
dock.add(resultsPanel);
}
at the beginning of my code I add the dock (DockLayoutPanel ) to my RootLayoutPanel.
as I show at the first image... with position set to absolute I can have the scrollbar and the results are cut, but if I disable position: absolute as shown in the second pic
the scrollbar is enabled and I can have full access to all of my results.
The scrollbar is set like this :
RootLayoutPanel.get().getWidgetContainerElement(dock).getStyle().setOverflowY(Overflow.AUTO);
What I am trying to do is remove position for every dockLayoutPanel's child or set it to something else that doesn't creates me a problem.
I found a solution. On CSS styling simply I had to write
.cw-DockPanel > div {
position : initial !important;
}
If anyone has to suggest a better way than to use !important i would be glad to hear it.
I made a grid of buttons in JavaFX.
When I resize the window with the grid inside, the buttons resize within the grid as well.
The problem is that the text on those buttons doesn't resize along with them: it stays the same size all the time, so when the buttons grow big, there's a lot of empty space on a button and then a tiny little text in the middle, which looks terrible.
I would rather like the text to automatically resize along with these buttons to fit the empty space, so that when the entire user interface gets bigger, the text on the buttons gets bigger as well.
How can I accomplish that?
I tried setting the -fx-font-size in the CSS stylesheet to percentage values, but it doesn't seem to work the same way as for websites: the text doesn't scale as a percentage of its container, but as a percentage of some predefined text size.
Edit
This is not a duplicate! Stop marking each question out there as duplicate! If it has been answered, I wouldn't have asked it in the first place!
From what I see, the first of those threads was about a situation where someone wanted to set the size/style of the text for newly-created buttons to account for the current size of their container etc. This is not what I need, because I want the buttons which has been already created as well to automatically resize their texts when these buttons resize inside their container in some way.
The other thread was about scaling the text along with the root container / window with a preset font size. This is also different from what I need, because I don't want the text to be scaled with the window, but with the sizes of the buttons themselves. And it has to be scaled in a certain way: to always fit the size of the button. You know: the text stays the same, but stretches so that it always fits the inside of the button (with a little padding, not a huge empty area around the text).
It is the button's size which is to determine the size of the text on it, not the window or container or something else, and it needs to be done automatically by the button itself (either the built-in one or a subclassed one), not manually by its encompassing container iterating over all these buttons and updating their text's sizes (which would be dumb way to do it).
This is, liked the linked questions, something of a hack: but consider scaling the text node inside the button instead of changing the font size. This seems to work ok:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
public class ScaledButtons extends Application {
#Override
public void start(Stage primaryStage) {
GridPane root = new GridPane();
root.setHgap(5);
root.setVgap(5);
for (int i = 1; i <= 9 ; i++) {
root.add(createScaledButton(Integer.toString(i)), (i-1) % 3, (i-1) / 3);
}
root.add(createScaledButton("#"), 0, 3);
root.add(createScaledButton("0"), 1, 3);
root.add(createScaledButton("*"), 2, 3);
primaryStage.setScene(new Scene(root, 250, 400));
primaryStage.show();
}
private Button createScaledButton(String text) {
Button button = new Button(text);
GridPane.setFillHeight(button, true);
GridPane.setFillWidth(button, true);
GridPane.setHgrow(button, Priority.ALWAYS);
GridPane.setVgrow(button, Priority.ALWAYS);
button.layoutBoundsProperty().addListener((obs, oldBounds, newBounds) ->
scaleButton(button));
button.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
return button ;
}
private void scaleButton(Button button) {
double w = button.getWidth();
double h = button.getHeight();
double bw = button.prefWidth(-1);
double bh = button.prefHeight(-1);
if (w == 0 || h == 0 || bw == 0 || bh == 0) return ;
double hScale = w / bw ;
double vScale = h / bw ;
double scale = Math.min(hScale, vScale);
button.lookup(".text").setScaleX(scale);
button.lookup(".text").setScaleY(scale);
}
public static void main(String[] args) {
launch(args);
}
}
An alternate approach to get a similar effect could be to subclass com.sun.javafx.scene.control.skin.ButtonSkin and override the layoutLabelInArea(double x, double y, double w, double h, Pos alignment) method from the skin's parent (LabeledSkinBase). You can then explicitly assign the updated skin to your button (either via CSS or via Java API calls).
Doing so would requires the subclassing of com.sun APIs which could change without notice in subsequent JavaFX releases. Also layoutLabelInArea is reasonably complex in its operation so changing the layout logic could be a little tricky. Certainly, James's suggestion of applying a text rescaling operation based upon a listener to the layout bounds property is simpler in this particular case.
I'm not necessarily advocating this approach, just providing a route to something that you could create that would satisfy your goal of: "It is the button's size which is to determine the size of the text on it, not the window or container or something else, and it needs to be done automatically by the button itself".
I'm writing a GUI in Java using Swing. At the moment, I'm trying to create a "Module" (a yellow block) that has a widget holder (black bar) on the left and right edges. Each holder will hold several small blocks that I'd like to display in a vertical line. Here is a picture:
Example module :
I want to be able to space the magenta/cyan blocks evenly along the widget holders.
I've looked at several tutorials for Swing and have tried implementing the layout of the widget holders as GridLayout and BoxLayout, but both without luck. A single column GridLayout seems to be the natural choice here, but I can't seem to make it work, even though I've written small test programs that properly use a grid.
The fact that the layout managers work in simple examples but not in this slightly more complex program has left me perplexed.
In my program,
The module is a JPanel
The widget holders / black bars are also JPanels
The widgets themselves (cyan/magenta blocks) are currently JPanels, but I've tried having them as JLabels and JButtons as well. I just want them to be able to listen to mouse events and to have an area and color.
On a side note, I was also having trouble with the layout of the Module itself to position the widget holders on the left and right. I tried using a horizontal BoxLayout (holder, horizontal glue, holder), and another time I tried using a BorderLayout (using EAST/WEST for either holder), but no matter what I did the holders would not budge - so as much as I didn't want to, I used setBounds() to position them.
Module Class (widget holders are inputLine and outputLine):
public class Module extends JPanel
{
private static final int MOD_WIDTH = 86;
private static final int MOD_HEIGHT = 60;
private int screenX, screenY, myX, myY;
private boolean moving = false;
// figure out the layout !
private JPanel inputLine, outputLine;
public Module()
{
//super(new BorderLayout());
initPanel();
initWidgets();
initMouse();
setLayout(null);
list();
}
private final void initPanel()
{
this.setSize(new Dimension(MOD_WIDTH, MOD_HEIGHT));
this.setBackground(Color.ORANGE);
}
private void initWidgets()
{
inputLine = new JPanel(new GridLayout(0, 1, 5, 5));
outputLine = new JPanel(new GridLayout(0, 1, 5, 5));
inputLine.setBounds (0, 0, 18, 60);
outputLine.setBounds(68, 0, 18, 60);
this.add(inputLine);
this.add(outputLine);
/* adding IOWidgets to test */
inputLine.add(new InputWidget());
inputLine.add(new InputWidget());
inputLine.add(new InputWidget());
outputLine.add(new OutputWidget());
outputLine.add(new OutputWidget());
outputLine.add(new OutputWidget());
outputLine.add(new OutputWidget());
inputLine.setBackground(Color.BLACK);
outputLine.setBackground(Color.BLACK);
}
Here is the abstract IOWidget class that both type of widgets (input[magenta], output[cyan]) derive from. It will have added functionality later.
public abstract class IOWidget extends JLabel
{
private static final int EDGE_SIZE = 8;
public IOWidget()
{
this.setSize(new Dimension(EDGE_SIZE, EDGE_SIZE));
}
}
Here is the InputWidget class. At the moment, it's identical to OutputWidget until I add the extra functionality, so I'll only post this one :
public class InputWidget extends IOWidget
{
public InputWidget()
{
this.setBackground(Color.MAGENTA);
}
}
In my application, modules are added to a larger JPanel. I would hope that the layout of the module is independent of how it's added to another JComponent, so I will omit the rest of the code.
Here is what the program looks like when run :
For completeness, here's the output of calling list on a single module :
rhopkins.honors.Dataflow.Module[,0,0,86x60,invalid,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=]
javax.swing.JPanel[,0,0,18x60,invalid,layout=java.awt.GridLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=]
rhopkins.honors.Dataflow.InputWidget[,0,0,8x8,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=8,height=8]]
rhopkins.honors.Dataflow.InputWidget[,0,0,8x8,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=8,height=8]]
rhopkins.honors.Dataflow.InputWidget[,0,0,8x8,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=8,height=8]]
javax.swing.JPanel[,68,0,18x60,invalid,layout=java.awt.GridLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=]
rhopkins.honors.Dataflow.OutputWidget[,0,0,8x8,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=8,height=8]]
rhopkins.honors.Dataflow.OutputWidget[,0,0,8x8,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=8,height=8]]
rhopkins.honors.Dataflow.OutputWidget[,0,0,8x8,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=8,height=8]]
rhopkins.honors.Dataflow.OutputWidget[,0,0,8x8,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=8,height=8]]
I'd very much like to know what I'm doing wrong. Also, I'm aware I'm new to Swing and GUI development in general, so any criticism about style/conventions/anything is welcome.
Dont use a null layout.
Your main panel should probably be a BorderLayout. You can add your widget holders to the WEST and EAST of your main panel.
The widget panel should be able to use a vertical BoxLayout. You will need to add glue before/after every widget you add to the panel. Since the BoxLayout respects the sizes of the component, you will need to override the getPreferredSize(), getMinimumSize() and getMaximumSize() methods to all return the same value. This way any extra space in the panel should be divided equally among the glue that you add.
I have a JTable inside of a JScrollPane. I am creating a custom cell editor for one of the columns of the table, and I want this editor to pop up a scrolling JList. I've done this by using a Popup to show a new JScrollPane containing the JList.
Everything is working, except for the position of the Popup. My custom component for the editor looks basically like this:
public class CustomPanel extends JPanel {
JTextField text = new JTextField();
JList list = new JList();
JScrollPane scroll = new JScrollPane(list);
Component owner = null;
public CustomPanel(Component owner) {
this.owner = owner;
add(text);
}
public void showPopup() {
Popup p = PopupFactory.getPopup(owner, scroll, getX(), getY()+getHeight());
p.show();
}
}
What is happening is that getX() and getY() are returning the position of the table cell relative to the JScrollPane holding it, and Popup is wanting absolute screen position. Even if I pass in owner the JScrollPane that they are relative to, it doesn't work. I get the same problem if I use text.getX() / text.getY().
How can I position my Popup directly below the TextBox?
Just a bit more background: The end goal is a multiple-select combobox that displays all of the selected items as a comma-separated list. If something else like this already exists, please don't hesitate to point me to it.
Edit: owner.getLocationOnScreen().y + getY() doesn't work when the scroll pane is anywhere but scrolled all the way up. However, just plain getLocationOnScreen().y DOES work. Problem solved, thank you.
You can query the absolute screen position with Component.getLocationOnScreen(). Is that what you're looking for?
I'm developing a an eclipse plugin that uses an SWT interface. I need to display text, and within that text there needs to be links. The only two widgets that I've found that will allow me to include clickable links in text are Link and Browser. Browser, however, is overkill for my needs, and I couldn't properly customize the look of it. This only leaves the Link widget.
The problem is I need the Link widget to inherit a gradient from the Composite in which it is in. It does this correctly, only when it is resized or scrolled the Link component flickers. The Link is the only component in which I have seen this effect.
In an attempt to fix this I've tried manipulating other components into having clickable links, but I haven't found a good solution yet.
Is there anyway to fix the flickering effect on the Link, or is there a different component which would support links?
Thanks,
Brian
After spending the day working on this, I came up with a workaround. I created a Composite for the text area. For each word that isn't part of a url,got its own label. For links, each letter got its own label. Then the labels for the url characters got a listener to launch a browser. Using this method provided the Link functionality, handled resizing properly, and has no flicker.
Have you tried passing SWT.NO_BACKGROUND to your Link widget? It might get a little strange... and you may have to do a little more work to get the gui drawing properly, but that would be my first guess.
Other than that, here's my Quick n' dirty implementation of a link inside of a StyledText. You will need to fill in for changing the cursor (if that's something you want), as well as coming up with a good "text to link" mapping scheme.
The only thing is I'm not sure if StyledText will inherit your background... give it a shot.
public class StyledTextExample {
public static void main(String [] args) {
// create the widget's shell
Shell shell = new Shell();
shell.setLayout(new FillLayout());
shell.setSize(200, 100);
Display display = shell.getDisplay();
// create the styled text widget
final StyledText widget = new StyledText(shell, SWT.NONE);
String text = "This is the StyledText widget.";
widget.setText(text);
widget.setEditable(false);
final StyleRange hyperlinkStyle = new StyleRange();
String linkWord = "StyledText";
hyperlinkStyle.start = text.indexOf(linkWord);
hyperlinkStyle.length = linkWord.length();
hyperlinkStyle.fontStyle = SWT.BOLD;
hyperlinkStyle.foreground = display.getSystemColor(SWT.COLOR_BLUE);
widget.setStyleRange(hyperlinkStyle);
widget.addMouseListener(new MouseAdapter() {
public void mouseUp(MouseEvent arg0) {
Point clickPoint = new Point(arg0.x, arg0.y);
try {
int offset = widget.getOffsetAtLocation(clickPoint);
if (widget.getStyleRangeAtOffset(offset) != null) {
System.out.println("link");
}
} catch (IllegalArgumentException e) {
//ignore, clicked out of text range.
}
}});
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch()) display.sleep();
}
}