Creating a closeable tab in Mono/GTK - mono

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);

Related

SWT ScrolledComposite horizonal and vertical scroll bar disabled

When I run my code scroll bars coming as disabled. I want to enabled it with fixed size. I am referring to this example and I have added ScrolledCompisite code in the creatContenyArea method. Appreciate suggestion on how to fix this thanks.
#Override
protected Composite createContentArea(Composite parent) {
ScrolledComposite sc = new ScrolledComposite(parent, SWT.H_SCROLL
| SWT.V_SCROLL);
sc.setMinSize(100, 100);
sc.setExpandHorizontal(true);
sc.setExpandVertical(true);
sc.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
sc.setAlwaysShowScrollBars(true);
Composite comp = super.createContentArea(sc);
comp.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
FillLayout layout = new FillLayout();
layout.marginWidth=5;
parent.getShell().setLayout(layout);
Link l = new Link(comp,SWT.NONE);
l.setText(
"This a custom tooltip you can: \n- pop up any control you want\n- define delays\n - ... \nGo and get Eclipse from <a>http://www.eclipse.org</a>");
l.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
l.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
openURL();
}
});
sc.setContent(comp);
return comp;
}

javafx TabPane setSelection doesn't switch the tab

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);
}
}

Horizontal scrollbar updating

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));
}

Context menu in windows 8 using Popup

Hi I am trying to create a context menu in windows 8 using Popup. On Right click of a button I am calling the following function
private async void UIElement_OnRightTapped(object sender, RightTappedRoutedEventArgs e)
{
PopupMenu popUpMenu = new PopupMenu();
popUpMenu.Commands.Add(new UICommand("File"));
Rect rect = GetRect(sender);
var result= await popUpMenu.ShowForSelectionAsync(rect, Placement.Right);
}
While defination for GetRect method is as follows:-
private Rect GetRect(object sender)
{
FrameworkElement element = sender as FrameworkElement;
GeneralTransform elementTransform = element.TransformToVisual(null);
Point point = elementTransform.TransformPoint(new Point());
Size size = new Size(element.ActualWidth, element.ActualHeight);
Rect rect = new Rect(point, size);
return rect;
}
Though the GetRect is returning correct value, but still i am getting result as null.
Please help
I can't figure out why you have this problems. On the first view, everything looks fine.
Maybe Tim Heuer Callisto package contains an easier approach for exactly what you want. See this example.
It's because you're not clicking on the File command, but instead clicking elsewhere on the page.

Why does the last JLabel I add to the JFrame move if I resize the window by dragging the corner with the mouse?

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)