GWT/GXT containers render position issues - gwt

While trying to insert absolute positioned HorizontalContainer into other container, I came upon weird issue. This absolute container pushes his next sibling by its width, if siblings are still being rendered (has a mask set).
Example:.
//parent container, holding all the widgets
HorizontalLayoutContainer hlc;
//widgets that are inserted into hlc container from the start
HBoxLayoutContainer hbox1;
HBoxLayoutContainer hbox2;
HBoxLayoutContainer hbox3;
//container that's inserted into hlc onMouseOver event. It can be inserted while hlc hboxes are still being rendered
HorizontalLayoutContainer panelContainer = new HorizontalLayoutContainer();
panelContainer.getElement().getStyle().setZIndex(13);
panelContainer.getElement().getStyle().setPosition(Position.ABSOLUTE);
panelContainer.getElement().getStyle().setWidth(55, Unit.PX);
panelContainer.getElement().getStyle().setHeight(18, Unit.PX);
panelContainer.getElement().getStyle().setFloat(Float.LEFT);
Now let's say a user hovers mouse over hlc container, which has hboxes1-3, however some of them has a mask set (data is still loading), like hbox1.mask(). onMouseOver event panelContainer is inserted into hlc:
hlc.insert(panelContainer, 0, new HorizontalLayoutData(55, 18));
However, since hboxes are still being rendered, panelContainer pushes hbox1 by 55px (its length) to the right. Even if it has position:absolute;.
left:55px; should be left: 0px;
-->
|panleContainer|hbox1|hbox2|hbox3|
Any suggestions how should I properly insert panelContainer? Why is absolute positioning being ignored?
Note:
If I wait for hboxes to be rendered, panelContainer is inserted properly, hbox1 is not pushed.
Clarification to avoid xy problem:
Short summary: add an absolutely positioned box (for clarity, let's call it DragBox) which has a predefined width to an existing container (WidgetBox). WidgetBox is a HorizontalLayoutContainer which has 2 or 3 HBoxLayoutContainers. WidgetBox children (HBoxLayoutContainers) have widths of percentages. Example: if WidgetBox has 2 children, their widths are 0.3 and 0.7, if 3 children, then widths are 0.3, 0.4, 0.3;
WidgetBox is sized by its parent (SimpleContainer->VerticalLayoutContainer->WidgetBox).
Expecting: When a mouse is hovered over any WidgetBox container, a new item (DragBox) is added as a first element of the WidgetBox. It should not affect WidgetBox children in anyway. It should act as an absolute (within WidgetBox bounds) box.
Result: If WidgetBox or its parent's layout is forced (through forceLayout()), then DragBox affects first WidgetBox child. If forceLayout() is not used, DragBox does not affect WidgetBox children.

Since forceLayout() in my case is used only to ensure proper WidgetBox children (see my edit) content formatting, I don't want to force children to be laid out for widgetBox.
To avoid this, I forced layout on each child of widgetBox instead of a parent.
Example:.
HorizontalLayoutContainer (parent)
-> HorizontalLayoutContainer (child 1, removed/added on mouseOver/Out)
-> HBoxLayoutContainer (child 2)
-> ...
I used to force layout on parent, like parent.forceLayout() which would force children to be laid out and parent container would be resized.
To avoid, as mentioned, I force layout on each child separately:
for(int i = 0; i < parent.getWidgetCount(); i++) {
if (parent.getWidget(i) instanceof ResizeContainer) {
ResizeContainer widget = (ResizeContainer) parent.getWidget(i);
widget.forceLayout();
}
}

Related

How to get rid of horizontal scrollbar in Material-UI TreeView?

When trying out the Material-UI basic example for Tree View (#mui/lab/TreeView), I do not know how to remove the horizontal scrollbar when using the overflowY: "auto" (The same effect even if I use overflow: "auto") option in the sx prop of the TreeView component. The horizontal scrollbar appears no matter how much space is available to the right. I want to keep the overflowY option in case of vertical overflow.
For example please see the basic tree view example from the official Material-UI page in StackBlitz or CodeSandbox.
How to remove the horizontal scrollbar when it's not needed?
This happens because the CSS classes .MuiTreeItem-content and its child .MuiTreeItem-label are set to 100% width by default, therefore, the .MuiTreeItem-content's 8px padding on x axis (also default) get in the way, adding 16px too many. You can easily override this by setting .MuiTreeItem-content's class padding to 0.
// ...
import MuiTreeItem from "#mui/lab/TreeItem";
import { styled } from "#mui/material/styles";
const TreeItem = styled(MuiTreeItem)(({ theme }) => ({
"& .MuiTreeItem-content": {
padding: 0,
},
}));
// ...
To remove the horizontal scrollbar completely you can hide the overflow over the X axis.
in css
.TreeView {
overflow-x: hidden;
}
or in jsx
<TreeView
sx={{ overflowX: "hidden" }}
...
>

AG Grid: How to stick the scrolling at bottom

i'm using AG Grid Angular to create a log view, i will add a lot of entries per second to the grid, typically this type of view's has the newest entry at the bottom, so it would be great if there is a good way where the scrolling will stick at the bottom, so i can always see the latest entry. A bonus would be, if i can manually scroll up and the scrolling will stay at this position.
Here's one way to do it:
handle rowDataChanged in your markup:
<ag-grid-angular
class="ag-dark"
[rowData]="messages"
[columnDefs]="columnDefs"
[gridOptions]="gridOptions"
(bodyScroll)="handleScroll($event)"
(rowDataChanged)="handleRowDataChanged($event)">
</ag-grid-angular>
In the handler for rowDataChanged, call ensureVisibleIndex to scroll to the last row added:
gridOptions: GridOptions = {
suppressScrollOnNewData: true,
}
handleRowDataChanged(event) {
const index = this.messages.length - 1;
this.gridOptions.api.ensureIndexVisible(index, 'bottom');
}
Demo:
https://stackblitz.com/edit/angular-ag-grid-stuck-to-bottom
In that code there is also some logic around when to keep the table scrolled to the end or not based on the scroll position.

Material UI v1 table with scroll (overflow: scroll)

How to create table with scroll overflow in Material UI v1 (v1-beta currently)? In component demos in MUI documentation there is no such example.
In all of the Table examples, there is a class applied to the div containing the Table that configures horizontal scrolling. It isn't apparent unless you're viewing the documentation with a sufficiently small viewport. (see BasicTable.js):
const styles = theme => ({
paper: {
width: '100%',
marginTop: theme.spacing.unit * 3,
overflowX: 'auto',
},
});
The paper class is applied to the root element:
function BasicTable(props) {
const classes = props.classes;
return (
<Paper className={classes.paper}>
<Table>
...
If you want a vertical scroll, you'll need to specify a height and include considerations for overflow-y. If you want both horizontal and vertical scrolling, you can set overflow and both axes will be configured:
const styles = theme => ({
paper: {
height: 300,
width: '100%',
marginTop: theme.spacing.unit * 3,
overflow: 'auto',
},
});
Note: This will not fix your column headings, because it is applied to the container. This adjustment will apply scrollbars to the entire table - heading, body, footer, etc.
In order to have the table header fixed and scroll just the table body I've come up with this solution.
First I added to each of the table components the component="div" property in order to get rid of the table skeleton completely.
Then I've added to Table, TableHead, TableBody and TableCell the display: block rule to override the material rules.
TableRows will get display: flex.
TableBody will get the desired fixed (max-)height, plus overflow: auto.
Of course by using divs instead of table tags the header and body cells lose the table alignment. In my case I solved this by setting to the first cells a fixed width, same for the first cells in the header and the first cells in body (or you can go for percentages as well) plus a flex-shrink: 0.
The second cells got flex-grow: 1
Note: Material UI v1 used
Use the "stickyHeader" property on table such as <Table stickyHeader>...</Table>

Differences btw Gtk.Table and Gtk.Grid

Althought Gtk.table is deprecated, I am getting better results with it, instead of the recommended Gtk.Grid.
It is probably my mistake, but I couldn't find the problem.
My aim is to create a Gtk window with a notebook at the top and two buttons below. These buttons should be horizontally aligned.
My code with table, works as expected:
uses Gtk
class TestWindow : Window
init
// General characteristics of the window
title = "Gtk Containers"
default_height = 250
default_width = 250
window_position = WindowPosition.CENTER
destroy.connect(Gtk.main_quit)
// Now building the notebook
var notebook = new Gtk.Notebook()
var label1 = new Gtk.Label("Page one")
var label2 = new Gtk.Label("Page two")
var child1 = new Gtk.Label("Go to page 2 for the answer")
var child2 = new Gtk.Label("Go to page 1 for the answer")
notebook.append_page(child1, label1)
notebook.append_page(child2, label2)
// Now building the table
var table = new Table(2,2,true)
var button1 = new Gtk.Button.with_mnemonic("Button_1")
var button2 = new Button.with_mnemonic("Button_2")
// Attaching all elements into the table
table.attach_defaults(notebook, 0,2,0,1)
table.attach_defaults(button1, 0,1,1,2)
table.attach_defaults(button2, 1,2,1,2)
add(table)
init
Gtk.init (ref args)
var test = new TestWindow ()
test.show_all ()
Gtk.main ()
However, the same code with the recommended Gtk.Grid gives me the two buttons without the notebook:
uses Gtk
class TestWindow : Window
init
// General characteristics of the window
title = "Gtk Containers"
default_height = 250
default_width = 250
window_position = WindowPosition.CENTER
destroy.connect(Gtk.main_quit)
// Now building the notebook
var notebook = new Gtk.Notebook()
var label1 = new Gtk.Label("Page one")
var label2 = new Gtk.Label("Page two")
var child1 = new Gtk.Label("Go to page 2 for the answer")
var child2 = new Gtk.Label("Go to page 1 for the answer")
notebook.append_page(child1, label1)
notebook.append_page(child2, label2)
// Now building the grid
var grid = new Grid()
var button1 = new Gtk.Button.with_mnemonic("Button_1")
var button2 = new Button.with_mnemonic("Button_2")
// Attaching all elements into the grid
grid.attach(notebook, 0,2,0,1)
grid.attach(button1, 0,1,1,2)
grid.attach(button2, 1,2,1,2)
init
Gtk.init (ref args)
var test = new TestWindow ()
test.show_all ()
Gtk.main ()
How to achieve the aim using Grid instead of Tables? Not asking for code, just a pointer.
gtk_table_attach_defaults() and gtk_grid_attach() operate differently. The official documentation in C points this out.
Given
thing.attach(widget, a,b,c,d)
For GtkTable, the four numbers a, b, c, and d are the actual column and row numbers that the given edge of the widget should occupy. a is the left edge, b is the right edge, c is the top edge, and d is the bottom edge.
For GtkGrid, a is the column and b is the row that the top-left corner of the widget should occupy, c is the number of columns wide the widget is, and d is the number of rows tall the widget is.
Or in other words,
table.attach_defaults(widget, left, right, top, bottom)
is the same as
grid.attach(widget, left, top,
right - left + 1, bottom - top + 1)
Hopefully some part of that explanation clears things up.
The quick fix for your code would be
grid.attach(notebook, 0,0,2,1)
grid.attach(button1, 0,1,1,1)
grid.attach(button2, 1,1,1,1)
For Gtk.Grid:
attach(child, left, top, width, height)
Parameters:
child (Gtk.Widget) – the widget to add
left (int) – the column number to attach the left side of child to
top (int) – the row number to attach the top side of child to
width (int) – the number of columns that child will span
height (int) – the number of rows that child will span
For Gtk.Table:
attach(child, left_attach, right_attach, top_attach, bottom_attach, xoptions, yoptions, xpadding, ypadding)
Parameters:
child (Gtk.Widget) – The widget to add.
left_attach (int) – the column number to attach the left side of a child widget to.
right_attach (int) – the column number to attach the right side of a child widget to.
top_attach (int) – the row number to attach the top of a child widget to.
bottom_attach (int) – the row number to attach the bottom of a child widget to.
xoptions (Gtk.AttachOptions) – Used to specify the properties of the child widget when the table is resized.
yoptions (Gtk.AttachOptions) – The same as xoptions, except this field determines behaviour of vertical resizing.
xpadding (int) – An integer value specifying the padding on the left and right of the widget being added to the table.
ypadding (int) – The amount of padding above and below the child widget.
Note: That the columns and rows are indexed from zero.
andlabs's explanation is correct, although his conversion adding 1 to grid.attach right and bottom values didn't work well to me. As I had to convert many of these values, I've prepared a python script to ease this process, HTH:
import sys
if len(sys.argv) < 2: raise Exception('Argument not provided')
args = ''.join([str(x) for x in sys.argv[1:]]).split(',')
if len(args) != 4: raise Exception('Please provide 4 attach arguments')
left, right, top, bottom = map(lambda a: int(a), args)
print("{}, {}, {}, {}".format(left, top, right - left, bottom - top))

Adding three or more widgets to a GWT LayoutPanel

I want to display three or more DataGrids in my LayoutPanel and specify their width as a percentage of the total width of the LayoutPanel, but in the LayoutPanel methods i see only methods for setting the width of the left and right widgets. setWidgetLeftWidth() and setWidgetRightWidth().
Is it possible to add more than 2 widgets to a LayoutPanel like
layoutPanel.add(dataGrid1);
layoutPanel.add(dataGrid2);
layoutPanel.add(dataGrid3);
layoutPanel.add(dataGrid4);
and then set the width of each widget to be 25% of the width of the LayoutPanel?
Thanks and regards
Mukul
What you have will work, all you need to do is to make each one setup like the following:
layoutPanel.add(dataGrid1);
layoutPanel.setWidgetLeftRight(dataGrid1, 0, Unit.PCT, 25, Unit.PCT);
Well I think you could do it with LayoutPanel too, but using the DockLayoutPanel is much easier! Here is the code for a the example you tried with a LayoutPanel.
public void onModuleLoad() {
//define a DockLayoutPanel with a Percentage size definition
DockLayoutPanel dockLayoutPanel = new DockLayoutPanel(Unit.PCT);
//add four widgets to the DockLayoutPanel, each with a Percentage
//with of 25%
dockLayoutPanel.addWest(new Label("widget 1"), 25);
dockLayoutPanel.addWest(new Label("widget 2"), 25);
dockLayoutPanel.addWest(new Label("widget 3"), 25);
//the last widget must always be added with the .add method
//since it takes the rest of the screen
dockLayoutPanel.add(new Label("widget 4"));
//set a with to the DockLayoutPanel (elso you don't se much)
dockLayoutPanel.setWidth("500px");
dockLayoutPanel.setHeight("500px");
//add it to the RootPanel
RootPanel.get().add(dockLayoutPanel);
}
So as long as you don't have a good reason why you must use LayoutPanel, I'd use the DocklayoutPanel!