I was messing around with SWT (for a PropertyPage), and found a little 'bug'?
Basically, when I resize the shell so it is smaller than my controls, it will make a scrollBar visible, which works just as intended. Though if I resize my controls (which are all children of a single root of course), somehow one or more parents don't get updated of the change which results in some weird behavior.
When my controls grow in size, it basically grows out of the shell (not visible) while there is no Scrollbar made visible. If I resize the shell (smaller than the initial size), the ScrollBar will become visible, but only for the initial size instead of the full width.
When my controls shrink in size it won't 'pack' either parent, which means I can scroll beyond the reach of my controls into emptiness.
Maybe it's worth mentioning that for me only horizontal growing/shrinking is a problem, although I'm pretty sure the same problems are occurring for vertical resizing
My question was if there is a solution/workaround for this. I have tried calling Layout() and pack() on various parents and the shell itself, without success. Now I know there is a custom (sadly private) Layout type used by one of the parents of a property page (the PreferenceDialog#PageLayout). Maybe this behavior comes this implementation?
EDIT: on request an MCVE
I assume one knows how to setup for a propertyPage, so for the sake of clarity I have posted only the createContents method (overriden from org.eclipse.jface.preference.PreferencePage), and a few helper methods/fields which should recreate a setup where this behavior can be observed. Basically play around with hiding/unhiding columns, and make sure to re-open when you want a different initial childSize (to test both growing and shrinking)
// static so you can re-open a the property/preference page for different initial sizes.
private static boolean h1 = false;
private static boolean h2 = false;
private static boolean h3 = false;
private static boolean h4 = false;
private Composite root;
#Override
protected Control createContents(Composite parent)
{
// setup root
this.root = new Composite(parent, SWT.NONE);
this.root.setLayout(new GridLayout());
this.root.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false));
Table table = new Table(this.root, SWT.SINGLE | SWT.VIRTUAL | SWT.BORDER | SWT.FULL_SELECTION);
table.setHeaderVisible(true);
table.setLinesVisible(true);
table.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false));
TableColumn c1 = new TableColumn(table, SWT.LEFT);
c1.setMoveable(true);
c1.setText("column 1");
this.updateColumn(c1, h1);
TableColumn c2 = new TableColumn(table, SWT.LEFT);
c2.setMoveable(true);
c2.setText("column 2");
this.updateColumn(c2, h2);
TableColumn c3 = new TableColumn(table, SWT.LEFT);
c3.setMoveable(true);
c3.setText("column 3");
this.updateColumn(c3, h3);
TableColumn c4 = new TableColumn(table, SWT.LEFT);
c4.setMoveable(true);
c4.setText("column 4");
this.updateColumn(c4, h4);
Button hide1 = new Button(this.root, SWT.PUSH);
hide1.setText("Hide column 1");
hide1.addListener(SWT.Selection, E -> {
this.updateColumn(c1, h1 = !h1);
this.resize();
});
Button hide2 = new Button(this.root, SWT.PUSH);
hide2.setText("Hide column 2");
hide2.addListener(SWT.Selection, E -> {
this.updateColumn(c2, h2 = !h2);
this.resize();
});
Button hide3 = new Button(this.root, SWT.NONE);
hide3.setText("Hide column 3");
hide3.addListener(SWT.Selection, E -> {
this.updateColumn(c3, h3 = !h3);
this.resize();
});
Button hide4 = new Button(this.root, SWT.PUSH);
hide4.setText("Hide column 4");
hide4.addListener(SWT.Selection, E -> {
this.updateColumn(c4, h4 = !h4);
this.resize();
});
for(int i = 0; i < 20; i++)
{
TableItem ti = new TableItem(table, SWT.NONE);
ti.setText(new String[] {"c1:" + i, "c2:" + i, "c3" + i, "c4" + i});
}
return root;
}
protected void updateColumn(TableColumn c, boolean hide)
{
if(hide)
{
c.setResizable(false);
c.setWidth(0);
}
else
{
c.setResizable(true);
c.setWidth(300);
}
}
protected void resize()
{
this.root.getDisplay().asyncExec(() -> this.root.getShell().layout(null, SWT.ALL | SWT.CHANGED));
}
Related
I want to control the TabPane and switch tabs with a Canvas, basically hide the tab headers and use canvas instead, the canvas displays different "Devices" and when user click on the device, the TabPane switch to show the content of that device.
fun canvasFlow_Click(mouseEvent: MouseEvent) {
val d = flowPresenter.click(mouseEvent)
if (d != null) {
flowPresenter.select(d)
logger.info("switch to ${d.position}")
tab.selectionModel.clearSelection()
tab.selectionModel.select(d.position)
}
}
Why select doesn't work? I don't see tab content changed. from log, I see "switch to 1", "switch to 2" correctly, just the tab doesn't switch! Why?
Note: this is plain javafx and might not be the exact solution in your case (hard to tell without example) - but actually I can reproduce the described behavior.
The problem seems to be calling clearSelection: TabPane with tabs should have exactly one selected tab - which is not specified. But every internal collaborator (skin, header, listener) goes to great lengths to guarantee that constraint - this assumption was wrong, in fact the skin gets confused if the selection changes to empty - the previously selected content is not removed. Might be a bug, either don't allow the selectionModel to be empty or improve the skin to cope with it (wondering how that would be supposed to look - hide the content?)
Anyway, here the solution is to not call that method before manually selecting a tab. There's no need to do so anyway, it's a SingleSelectionModel so takes care of allowing at most one item selected.
An example: un/comment the clearSelection and see how the content is not/ correctly updated with/out the call.
public class TabPaneSelection extends Application {
private Parent createContent() {
TabPane pane = new TabPane();
HBox headers = new HBox();
for (int i = 0; i < 3; i++) {
int index = i;
Tab tab = new Tab("header " + i, new Label("content " + i));
pane.getTabs().add(tab);
Button button = new Button(tab.getText());
button.setOnAction(e -> {
// do __not__ clear selection
//pane.getSelectionModel().clearSelection();
pane.getSelectionModel().select(index);
});
headers.getChildren().add(button);
}
BorderPane content = new BorderPane(pane);
content.setTop(headers);
return content;
}
#Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent(), 400, 300));
//stage.setTitle(FXUtils.fxVersion());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I am trying to use BooleanFieldEditor instead of Button with style SWT.CHECK. And I am getting the problem with layout of the checkbox.
The significant part of my previous code is:
Composite projectGroup = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 1;
projectGroup.setLayout(layout);
projectGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
Button checkBox = new Button(projectGroup, SWT.CHECK);
checkBox.setText(Messages.getString("WizardNewProjectCreationPage.createEmptyProject")); //$NON-NLS-1$
checkBox.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent event) {
Button button = (Button) event.getSource();
shouldEmptyProjectBeCreated = button.getSelection();
}
});
It gives me this result:
In this case the checkbox has a small indent at the top and the left side.
The significant part of my current code is:
Composite projectGroup = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().extendedMargins(100, 0, 100, 0).spacing(100, 100).applyTo(projectGroup);
BooleanFieldEditor emptyProjectCheckbox = new BooleanFieldEditor("createEmptyProject",
Messages.getString("WizardNewProjectCreationPage.createEmptyProject"), projectGroup);
// GridDataFactory.defaultsFor(projectGroup).grab(true, false).span(2, 1).applyTo(projectGroup);
// emptyProjectCheckbox.fillIntoGrid(projectGroup, 1);
createEmptyProject = emptyProjectCheckbox.getBooleanValue();
Whatever values I set into extendedMargins() and spacing() methods, the result is the same - checkbox is located strictly at the level of the upper frame:
As you can see, in this case indents are smaller than on the first picture. I want to make the same indents as on the first image and want to understand, how to manage the location of BooleanFieldEditor's checkbox relatively to another elements.
Using second composite solves the problem:
Composite projectGroup = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().extendedMargins(5, 0, 5, 0).applyTo(projectGroup);
//intermediate composite, which needs to work around the problem with layout of checkbox of BooleanFieldEditor
Composite intermediateComposite = new Composite(projectGroup, SWT.NONE);
BooleanFieldEditor emptyProjectCheckbox = new BooleanFieldEditor("createEmptyProject",
Messages.getString("WizardNewProjectCreationPage.createEmptyProject"), intermediateComposite);
createEmptyProject = emptyProjectCheckbox.getBooleanValue();
I'm developing an app that uses drag & drop operations. The drag & drop part includes four containers as drop targets and two draggable labels.
The app works as expected in the simulator, but when I install it on my Android phone, the background of the dialog (otherwise white) turns black for a swift moment as soon as the draggable components (labels) are released (then gets back to the original light color).
In the theme builder, I have set the background of the dialog to an almost white color (unselected, selected, pressed, disabled), but that doesn't show any effect.
Is there any turnaround to keep the background color stable? Any help would be appreciated.
Here is the relevant code excerpt:
Dialog dialog_W1 = new Dialog();
dialog_W1.setScrollableY(true);
dialog_W1.setLayout(new BoxLayout(2));
dialog_W1.setScrollableY(true);
dialog_W1.setTitle("Acerte o bichinho");
Image img_Cat = Image.createImage("/cat.png");
ScaleImageLabel label_Scaled_Image = new ScaleImageLabel(img_Cat);
label_Scaled_Image.setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FIT);
label_Scaled_Image.setUIID("NewLabel");
Label label_1 = new Label("ga");
Label label_2 = new Label("to");
label_1.setUIID("LabelWord");
label_2.setUIID("LabelWord");
label_1.setDraggable(true);
label_2.setDraggable(true);
Container c_1 = new Container();
Container c_2 = new Container();
Container c_3 = new Container();
Container c_4 = new Container();
c_1.setDropTarget(true);
c_2.setDropTarget(true);
c_3.setDropTarget(true);
c_4.setDropTarget(true);
c_1.setLayout(new BoxLayout(2));
c_2.setLayout(new BoxLayout(2));
c_3.setLayout(new BoxLayout(2));
c_4.setLayout(new BoxLayout(2));
c_1.setUIID("Container_1");
c_2.setUIID("Container_1");
c_3.setUIID("Container_2");
c_4.setUIID("Container_2");
c_3.add(label_2);
c_4.add(label_1);
GridLayout gl = new GridLayout(2,2);
Container container_0 = new Container(gl);
container_0.add(c_1);
container_0.add(c_2);
container_0.add(c_3);
container_0.add(c_4);
ArrayList <Container> list_Containers = new ArrayList<>();
list_Containers.add(c_1);
list_Containers.add(c_2);
list_Containers.add(c_3);
list_Containers.add(c_4);
ArrayList <Label> list_Labels = new ArrayList<>();
list_Labels.add(label_1);
list_Labels.add(label_2);
for (Label label : list_Labels) {
label.addDragOverListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (Container c : list_Containers) {
int int_C = c.getComponentCount();
if (int_C == 1) {
c.setDropTarget(false);
} else if (int_C == 0) {
c.setDropTarget(true);
}
}
}
});
}
I suggest showing the Dialog as a modless dialog instead of using the show method use showModless() or similar.
Odd things like this can happen because of the EDT nesting inherent in modal dialogs, normally we don't recommend using dialog for anything more than simple notifications. When we use drag and drop from a dialog like component we use InteractionDialog.
When I run this program, the panel with the 6 buttons appears as it should on the bottom of the screen, and the first 3 labels appear as they should and where they should, but the last label appears at about the center of the screen. Furthermore, when I click and drag on the bottom right corner of the window (resizing the window), the panel and the last label move so they stay in their relative positions with the size of the window but the first 3 labels stay in their designated positions. When I uncomment the line of code towards the bottom that adds a blank JLabel, all 4 labels are now in their correct spots and only the panel moves when I resize the window. Could someone please explain what is going on here? Thanks in advance!
import javax.swing.*;
import java.awt.*;
public class X extends JFrame{
private JPanel panel;
private JButton buttons[];
private JLabel labels[];
private Icon images[];
public X()
{
panel = new JPanel();
panel.setPreferredSize(new Dimension(470,110));
buttons = new JButton[6];
labels = new JLabel[4];
Dimension dim = new Dimension(75,100);
labels = new JLabel[4];
images = new Icon[6];
for(int i = 0; i<6;i++)
images[i] = new ImageIcon(getClass().getResource("image" + i + ".gif"));
int j = 5;
while( j >= 0 ){
Icon image = images[j];
buttons[j] = new JButton(image);
buttons[j].setPreferredSize(dim);
panel.add(buttons[j]);
j--;
}
add(panel, BorderLayout.SOUTH);
j = 3;
while( j>=0){
Icon image = new ImageIcon(getClass().getResource("image6.gif"));
labels[j] = new JLabel(image);
labels[j].setPreferredSize(dim);
if (j==3){
labels[j].setBounds(200,135,75,100);
}
else if (j==2){
labels[j].setBounds(313,70,75,100);
}
else if (j==1){
labels[j].setBounds(425,135,75,100);
}
else if (j==0){
labels[j].setBounds(313,200,75,100);
}
add(labels[j]);
j--;
}
// add(new JLabel());
}
public static void main(String[] args) {
X frame = new X();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(700,500);
frame.setVisible(true);
}
}
1) You should read Javadocs for JPanel/JButton/JLabel and their default behaviours.
2) You should make sure that the code which you post compiles
3) You should make sure that the code AS you post it illustrates your problem
As it is your post does not meet requirements 2) and 3) and you probably did not read enough of 1)
I'm trying to create new GTK Notebook tabs that contain both a name (as a Label) and a close button (as a Button with an Image) with the following code:
Label headerLabel = new Label();
headerLabel.Text = "Header";
HBox headerBox = new HBox();
Button closeBtn = new Button();
Image closeImg = new Image(Stock.Close, IconSize.Menu);
closeBtn.Image = closeImg;
closeBtn.Relief = ReliefStyle.None;
headerBox.Add(headerLabel);
headerBox.Add(closeBtn);
headerBox.ShowAll();
MyNotebook.AppendPage(childWidget, headerBox);
This seems to work just fine; however, the button is about 1.5 - 2 times the size is needs to be, so there is a lot of extra space around the image inside the button. Having looked at remove inner border on gtk.Button I now see that the culprit is the "inner-border" style property of the GtkButton, but (being new to GTK) I can't seem to figure out how to override its value.
Is there some method of doing this that I'm missing? I don't have any reservations about not using a Button/Image combination, so any more obvious suggestions are welcome.
Note: I have seen the suggestion in the linked question to use an EventBox, but I was not able to add the Relief and mouseover effects to that Widget.
You are in luck. I just made the exact same thing yesterday, and can fortunately give you some code. The trick is to create a Custom Tab Widget.
public class MultiTab : Gtk.Box
{
public Gtk.Label Caption;
Gtk.Image img = new Gtk.Image(Platform.IMG + "tab_close.ico");
public Gtk.ToolButton Close;
public Gtk.Notebook _parent;
public MultiTab ( string name )
{
CreateUI(name);
}
public MultiTab(string name, Gtk.Notebook parent)
{
_parent = parent;
CreateUI(name);
CreateHandlers();
}
void CreateUI(string name)
{
Caption = new Gtk.Label(name);
Close = new Gtk.ToolButton(img,"");
PackStart( Caption );
PackStart( Close );
ShowAll();
Close.Hide();
}
void CreateHandlers()
{
Close.Clicked += delegate {
_parent.RemovePage(_parent.CurrentPage);
};
}
public bool Active;
}
Next all you have to do is use this widget(or a similar one created by you) in Gtk.Notebook like this:
MyNoteBook.AppendPage(new <YourPage>(), new MultiTab("<your caption>",this));
And You're done.
Here is a screenshot:
Add this:
RcStyle rcStyle = new RcStyle ();
rcStyle.Xthickness = 0;
rcStyle.Ythickness = 0;
closeBtn.ModifyStyle (rcStyle);
Add items to box using Gtk.Box.PackStart/PackEnd methods rather than generic Gtk.Container.Add method. PackStart/PackEnd will allow you control how child widgets will be allocated space:
headerBox.PackStart (headerLabel, true, true, 0);
headerBox.PackEnd (closeBtn, false, false, 0);