I have a composite element, that initially has a Label. Now I call dispose on the it (the label) and create another label in the same container (composite elm), but I don't see the new text. It brings me to question how do I enable redraw on the composite, so that the new label (or any other component I might create) will render in place of the old one.
Here is the code I have (separated into a unit test for redraw a composite)
private Label createLabel( Composite parent) {
Label label = new Label(parent, SWT.NONE);
label.setAlignment(SWT.CENTER);
label.setLayoutData( new GridData( SWT.CENTER, SWT.CENTER, true, true) );
return label;
}
private void changeText() {
assert testCell != null : "Please initialize test cell";
testCell.getChildren()[0].dispose();
Label l = createLabel(testCell);
l.setText("New TexT");
testCell.redraw();
}
private void draw() {
Display display = new Display();
shell = new Shell(display);
shell.setLayout(new GridLayout(2,false));
testCell = new Composite(shell,SWT.BORDER);
testCell.setLayout(new GridLayout());
Label l = createLabel(testCell);
l.setText("Old Text");
Composite btnCell = new Composite(shell,SWT.NONE);
btnCell.setLayout(new GridLayout());
Button b = new Button(btnCell, SWT.PUSH);
b.setText("Change");
b.addListener(SWT.MouseDown, new Listener() {
public void handleEvent(Event e) {
changeText();
}
});
As you can see, I am calling redraw on the composite after I add a new element. Also, I have verified that after the call to dispose, testCell.getChildren().length returns 0, as expected, and when I create a new label, I get the same expression to return 1, verifying that the new element is indeed getting added to its parent composite container
Am I missing something here ?
In the changeText() function, the
testCell.redraw();
line should be replaced by
testCell.layout();
Or, if you want to resize it correctly you should use
shell.layout();.
I would say add a selectionListener on the label.
.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(final SelectionEvent e) {
//Change text by Label.setText();
}
}
Related
I am building a SWT application and have a menu created. Menu has multiple menu items like Add, Edit, Help. On click of each Menu Item, I want to show a composite which will display the details of it. I am able to build it, problem I am facing is, the space of hidden composite is not taken by visible composite. How can we make the composite occupy the entire space.
Also I am adding the selection listener to make the current composite visible and other composite hidden. In the current app there will multiple menu items and each one will have composite associated it. Listener needs reference of all composites to make them visible/hidden. Is there any better approach to do this.
public class MenuToggle {
boolean startup = true;
Menu menu, fileMenu, helpMenu;
Composite composite1,composite2;
public MenuToggle(Shell shell) {
createMenu(shell);
createFileView(shell);
createHelpView(shell);
startup = false;
}
public void createMenu(Shell shell) {
//Menu Bar
menu = new Menu(shell, SWT.BAR);
//File Menu
fileMenu = new Menu(shell, SWT.DROP_DOWN);
MenuItem fileMenuHeader = new MenuItem(menu, SWT.CASCADE);
fileMenuHeader.setText("&File");
fileMenuHeader.setMenu(fileMenu);
MenuItem fileSaveItem = new MenuItem(fileMenu, SWT.PUSH);
fileSaveItem.setText("&Save");
MenuItem fileExitItem = new MenuItem(fileMenu, SWT.PUSH);
fileExitItem.setText("E&xit");
//Help Menu
helpMenu = new Menu(shell, SWT.DROP_DOWN);
MenuItem helpMenuHeader = new MenuItem(menu, SWT.CASCADE);
helpMenuHeader.setText("&Help");
helpMenuHeader.setMenu(helpMenu);
MenuItem helpGetHelpItem = new MenuItem(helpMenu, SWT.PUSH);
helpGetHelpItem.setText("&Get Help");
shell.setMenuBar(menu);
fileSaveItem.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
composite1.setVisible(true);
((GridData)composite1.getLayoutData()).exclude = false;
composite2.setVisible(false);
((GridData)composite2.getLayoutData()).exclude = true;
composite2.layout(true, true);
}
});
helpGetHelpItem.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
composite1.setVisible(false);
((GridData)composite1.getLayoutData()).exclude = true;
composite2.setVisible(true);
((GridData)composite2.getLayoutData()).exclude = false;
composite2.layout(true, true);
}
});
}
public void createFileView(Shell shell) {
composite1 = new Composite(shell, SWT.BORDER);
composite1.setVisible(true);
GridData gd1 = new GridData(SWT.FILL, SWT.FILL, true, true);
composite1.setLayoutData(gd1);
composite1.setLayout(new GridLayout(1,true));
Label label = new Label(composite1, SWT.CENTER);
label.setBounds(composite1.getClientArea());
label.setText("Saved");
}
public void createHelpView(Shell shell) {
composite2 = new Composite(shell, SWT.BORDER);
composite2.setVisible(false);
GridData gd2 = new GridData(SWT.FILL, SWT.FILL, true, true);
composite2.setLayoutData(gd2);
composite2.setLayout(new GridLayout(1,true));
Label label1 = new Label(composite2, SWT.CENTER);
label1.setBounds(composite2.getClientArea());
label1.setText("No worries!");
}
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
shell.setText("Menu Display");
MenuToggle instance = new MenuToggle(shell);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
There are a number of issues here.
You are using FillLayout for the Shell layout, so the GridData you are setting on the composites is ignored. You must use GridLayout for the Shell:
public static void main(final String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout()); // Changed
When you change the exclude settings you must call layout on the parent of the composite - the shell:
fileSaveItem.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(final SelectionEvent e) {
composite1.setVisible(true);
((GridData)composite1.getLayoutData()).exclude = false;
composite2.setVisible(false);
((GridData)composite2.getLayoutData()).exclude = true;
shell.layout(true, true); // change
}
});
helpGetHelpItem.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(final SelectionEvent e) {
composite1.setVisible(false);
((GridData)composite1.getLayoutData()).exclude = true;
composite2.setVisible(true);
((GridData)composite2.getLayoutData()).exclude = false;
shell.layout(true, true); // change
}
});
You are calling setBounds on the Label controls, this does not work when you are using layouts because the layout also calls setBounds and overrides your settings, use setLayoutData instead
Label label = new Label(composite1, SWT.CENTER);
label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); // replace
//label.setBounds(composite1.getClientArea()); // wrong
As for dealing with lots of Composite controls you could call shell.getChildren and loop through the child controls. Or add the composites to a List and loop through that.
I'm sadly far from being an expert in SWT and RCP, but I really tried my best here... I can't figure out how to configure the widgets to get this layout (just a Photoshopped screen, never worked this way):
This is what I get if I set the column number of the GridLayout to 2:
Here is the Refresh and the Blacklist button in the wrong row, but at least everything is visible...
And this is what I get if I set the column number of the GridLayout to 3:
This is total messed up... Most of the widgets are pushed outside the visible area. DatePicker, Refresh, Whitelist and the Calculate buttons are not visible, they are somewhere outside on the right.
This is the codepart for this screen area:
resultingProductsGroup = new Group(propProdGroup, SWT.NONE);
final GridData gd_resultingProductsGroup = new GridData(SWT.FILL,
SWT.CENTER, true, false);
gd_resultingProductsGroup.widthHint = 240;
resultingProductsGroup.setLayoutData(gd_resultingProductsGroup);
resultingProductsGroup.setText("Resulting products");
final GridLayout gridLayout_4 = new GridLayout();
gridLayout_4.numColumns = 2;
resultingProductsGroup.setLayout(gridLayout_4);
Label refDateLabel = new Label(resultingProductsGroup, SWT.NONE);
refDateLabel.setText("Reference date:");
refDateInput = new DateInput(resultingProductsGroup, SWT.BORDER);
refDateInput.setLayoutData(new GridData());
refDateInput.setValue(new Date());
calculateProductsButton1 = new Button(resultingProductsGroup, SWT.NONE);
setupImageButton(calculateProductsButton1, Images.getButtonRefresh());
calculateProductsButton1.setLayoutData(new GridData());
GridDataFactory.swtDefaults().hint(18, 18).applyTo(
calculateProductsButton1);
resultingProductsTable = new TableListWidget<Product>(
resultingProductsGroup, SWT.BORDER, ListWidgetMode.MULTI);
resultingProductsTable.setLinesVisible(true);
resultingProductsTable.setHeaderVisible(true);
final GridData rpTableProperty = new GridData(SWT.FILL, SWT.FILL, true,
true, 3, 1);
resultingProductsTable.setLayoutData(rpTableProperty);
GridDataFactory.swtDefaults().hint(230, 240).applyTo(
resultingProductsTable);
setupResultingProductsTableColumns();
resultingProductsTable.sortByComparator(new Comparator<Product>() {
#Override
public int compare(Product o1, Product o2) {
return o1.getPartNum().getExternalId().compareTo(
o2.getPartNum().getExternalId());
}
});
resultingProductsTable.addOpenListener(new IOpenListener() {
#Override
public void open(OpenEvent event) {
doResultingProductsTableOpen();
}
});
calculateProductsButton2 = new Button(resultingProductsGroup, SWT.NONE);
calculateProductsButton2.setText("Calculate");
whitelistAddButton = new Button(resultingProductsGroup, SWT.NONE);
whitelistAddButton.setText("Whitelist");
whitelistAddButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(final SelectionEvent e) {
doAddToWhitelist();
}
});
blacklistAddButton = new Button(resultingProductsGroup, SWT.NONE);
blacklistAddButton.setText("Blacklist");
blacklistAddButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(final SelectionEvent e) {
doAddToBlacklist();
}
});
What am I not seeing here? I'm stuck with this GUI bug for over 2 days now... Please, help me :)
You could design the whole composite with one GridLayout and 3 columns, while using horizontal span of 3 on the table. That doesn't give you the desired mocked up screen though, because reference date controls and buttons at the bottom would be aligned in columns.
Try instead using 3 composites
reference date: row layout
table: fill layout
button list: row layout
I am creating a legend view and inside the shell is supposed to have a rectangle followed by a label describing the color. I was able to get the view to work using just a normal composite but the legend continues beyond the screen and no way of see it without making the window larger. I am trying to use a scrolledComposite view for my shell but when I execute the program, nothing appears.
public void createPartControl(Composite parent)
{
display = parent.getDisplay();
parent.setLayout(new FillLayout());
sc = new ScrolledComposite(parent, SWT.V_SCROLL | SWT.H_SCROLL);
LegendView.composite = new Composite(sc, SWT.NONE);
RowLayout layout = new RowLayout();
layout.wrap = true;
layout.spacing = 5;
composite.setLayout(layout);
}
public static void addRectangle(String legendMessage)
{
final String propId = legendMessage;
final String[] s = propId.split(",");
if (display != null)
{
display.syncExec(new Runnable()
{
#Override
public void run()
{
// Creating the color using the RBG values
final Color color =
new Color(display, Integer.parseInt(s[0]), Integer.parseInt(s[1]), Integer.parseInt(s[2]));
// Creating a canvas for which the rectangle can be drawn on
Canvas canvas = new Canvas(composite, SWT.NONE);
// Maybe set the bounds of the canvas
canvas.addPaintListener(new PaintListener()
{
public void paintControl(PaintEvent e)
{
e.gc.drawRectangle(1, 1, 50, 60);
e.gc.setBackground(color);
e.gc.fillRectangle(2, 2, 49, 59);
}
});
// Disposing the color after it has been used
canvas.addDisposeListener(new DisposeListener()
{
public void widgetDisposed(DisposeEvent e)
{
color.dispose();
}
});
// Creating a label and setting the font
Label label = new Label(composite, SWT.NULL);
Font boldFont = new Font( label.getDisplay(), new FontData( "Arial", 12, SWT.BOLD ) );
label.setFont( boldFont );
label.setText(s[3]);
composite.redraw();
composite.layout(true);
sc.setContent(composite);
}
});
}
}
I am calling add rectangle in a different class. I am fairly new at using SWT and after looking at examples and reading the docs for scrolled Composite, this is what I interpreted it as. Any help would be very appreciated.
You haven't told the ScrolledComposite how to manage the size. You must either call setSize or setMinSize. For this you probably want:
sc.setExpandHorizontal(true);
sc.setExpandVertical(true);
sc.setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
I have two comboviewer and the idea is that the second combo will display a subset of options depending of the first combo value selected. But after to set the new input in the second combo and refresh the combo width is too small. How can I set it for auto adjusting to options width?
public class ExpresionDialog extends Dialog {
private ComboViewer combo1;
private ComboViewer combo2;
#Override
protected Control createDialogArea(Composite composite) {
Composite parent = (Composite) super.createDialogArea(composite);
GridData data = new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1);
combo1 = new ComboViewer(parent);
combo1.setLabelProvider(new LabelProvider());
combo1.setContentProvider(ArrayContentProvider.getInstance());
combo1.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent e) {
IStructuredSelection sel = (IStructuredSelection) e.getSelection();
AttributeOption option = (AttributeOption) sel.getFirstElement();
combo2.setInput(getValuesCombo2(option));
combo2.refresh(true);
}
});
combo1.setInput(getValuesCombo1());
combo2 = new ComboViewer(parent);
combo2.setLabelProvider(new LabelProvider());
combo2.setContentProvider(ArrayContentProvider.getInstance());
return parent;
}
// Omitted getValuesCombo1 and getValuesCombo2 methods ...
}
You need to call the layout method of the parent Composite to get it to redo the child layouts each time you change the contents.
Is there a standard SWT control that resembles a button which displays an arrow and opens a dropdown menu when pressed and is not a toolbar-only control?
It would be something like this:
It is similar to a combo box control, except that the "button" area would act more similarly to an actual button - its text would not change based on your selection, it would appear depressed when clicked, and the items would be used for actions or navigational purposes instead of for selection. It's also similar to a control available for toolbars, but I need to use it on a regular composite instead.
This is nearly doable simply by using regular button and popup-menu controls - however, I do not believe I can display the arrow next to the text on the button this way. Anyway, since this kind of control seems fairly common, I assumed there would be a standard way to use these two things as one.
I think, this is what you should do get Drop down menu behavior
Create Menu with style SWT.DROP_DOWN
Create MenuItems on Menu
if you want a button
Create a Button with style SWT.ARROW | SWT.DOWN
add SelectionListener
In SelectionListener, Create a Menu with style SWT.POP_UP and position the menu at the button location.
//code
public static void main(String[] args) {
Display display = new Display();
final Shell shell = new Shell(display);
shell.setSize(300, 200);
shell.setText("Button Example");
shell.setLayout(new RowLayout());
/**
*
* Approach1
*
*/
final Composite btnCntrl = new Composite(shell, SWT.BORDER);
btnCntrl.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
btnCntrl.setBackgroundMode(SWT.INHERIT_FORCE);
GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).spacing(0, 1).applyTo(btnCntrl);
CLabel lbl = new CLabel(btnCntrl, SWT.NONE);
lbl.setText("Animals");
Button btn = new Button(btnCntrl, SWT.FLAT|SWT.ARROW|SWT.DOWN);
btn.setLayoutData(new GridData(GridData.FILL_VERTICAL));
btn.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
super.widgetSelected(e);
Menu menu = new Menu(shell, SWT.POP_UP);
MenuItem item1 = new MenuItem(menu, SWT.PUSH);
item1.setText("Hare");
MenuItem item2 = new MenuItem(menu, SWT.PUSH);
item2.setText("Fox");
MenuItem item3 = new MenuItem(menu, SWT.PUSH);
item3.setText("Pony");
Point loc = btnCntrl.getLocation();
Rectangle rect = btnCntrl.getBounds();
Point mLoc = new Point(loc.x-1, loc.y+rect.height);
menu.setLocation(shell.getDisplay().map(btnCntrl.getParent(), null, mLoc));
menu.setVisible(true);
}
});
/***
*
*
* Approach 2
*
*/
final Composite btnCntrl2 = new Composite(shell, SWT.BORDER);
btnCntrl2.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
btnCntrl2.setBackgroundMode(SWT.INHERIT_FORCE);
GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).spacing(0, 1).applyTo(btnCntrl2);
CLabel lbl2 = new CLabel(btnCntrl2, SWT.NONE);
lbl2.setText("Animals");
Button btn2 = new Button(btnCntrl2, SWT.FLAT|SWT.ARROW|SWT.DOWN);
btn2.setLayoutData(new GridData(GridData.FILL_VERTICAL));
btn2.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
super.widgetSelected(e);
Shell menu = (Shell) btnCntrl2.getData("subshell");
if(menu != null && !menu.isDisposed()){
menu.dispose();
}
menu = new Shell(shell, SWT.NONE);
menu.setLayout(new FillLayout());
Table table = new Table(menu, SWT.FULL_SELECTION);
table.addListener(SWT.MeasureItem, new Listener() {
#Override
public void handleEvent(Event event) {
event.height = 20; //TODO: determine later
}
});
table.addListener(SWT.PaintItem, new Listener() {
#Override
public void handleEvent(Event event) {
Rectangle bounds = event.getBounds();
event.gc.setBackground(event.display.getSystemColor(SWT.COLOR_BLUE));
event.gc.drawLine(bounds.x, bounds.y+bounds.height-1, bounds.x+bounds.width, bounds.y+bounds.height-1);
}
});
TableItem tableItem= new TableItem(table, SWT.NONE);
tableItem.setText(0, "Hare");
TableItem tableItem2= new TableItem(table, SWT.NONE);
tableItem2.setText(0, "Pony" );
TableItem tableItem3= new TableItem(table, SWT.NONE);
tableItem3.setText(0, "Dog");
Point loc = btnCntrl2.getLocation();
Rectangle rect = btnCntrl2.getBounds();
Point mLoc = new Point(loc.x, loc.y+rect.height);
menu.setLocation(shell.getDisplay().map(btnCntrl2.getParent(), null, mLoc));
menu.pack();
menu.setVisible(true);
btnCntrl2.setData("subshell", menu);
}
});
display.addFilter(SWT.MouseDown, new Listener() {
#Override
public void handleEvent(Event event) {
Shell shell = (Shell) btnCntrl2.getData("subshell");
if(shell != null && !shell.getBounds().contains(event.display.map((Control)event.widget, null, new Point(event.x, event.y)))){
shell.dispose();
btnCntrl2.setData("subshell", null);
}
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
This snippet shows how to use the described widget in a SWT toolbar. You can set the button text by using the item.setText() method.
This question is almost 10 years old, but just in case someone is still looking for a solution (like I just did ;) ):
I achieved a pretty close behaviour of your description using only a Button and a Menu using this approach: http://eclipseo.blogspot.com/2012/07/show-context-menu-programmatically.html
Button button = new Button(parent, SWT.PUSH);
button.setText("Animals");
Menu menu = new Menu(button);
MenuItem item = new MenuItem(menu, SWT.PUSH);
item.setText("hare");
menu.addListener(SWT.Show, new Listener() {
#Override
public void handleEvent(Event event) {
menu.setVisible(true);
}
});
button.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
menu.notifyListeners(SWT.Show, null);
}
});
The result is that the menu is shown when you (left) click on the button.
Bonus: to achieve the expand icon at the end, you can add a unicode character for a down triangle in the button text like so:
button.setText("Animals \u2BC6");
HTH,
Ben