Differences btw Gtk.Table and Gtk.Grid - gtk

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

Related

Can I set an ag-grid full-width row to have autoHeight?

I am trying to render a set of footnotes at the end of my data set. Each footnote should be a full-width row. On the docs page for row height, it says that you can set an autoHeight property for the column you want to use to set the height. Full-width rows, however, aren't tied to any column, so I don't think there's a place to set that autoHeight property.
For reference, here is my cell renderer, which gets invoked if a flag in the data object is true.
import { Component } from '#angular/core';
import { ICellRendererComp, ICellRendererParams } from '#ag-grid-community/core';
#Component({
template: '',
})
export class FootnoteRendererComponent implements ICellRendererComp {
cellContent: HTMLElement;
init?(params: ICellRendererParams): void {
this.cellContent = document.createElement('div');
this.cellContent.innerHTML = params.data.title;
this.cellContent.setAttribute('class', 'footnote');
}
getGui(): HTMLElement {
return this.cellContent;
}
refresh(): boolean {
return false;
}
}
The footnote (the "title" property above) could be one line or several depending on its length and the browser's window size. There may also be several footnotes. Is there a way to set autoHeight for each footnote row? Thanks for any help!
Not sure of CSS autoHeight can be use, but here is some example for calculating height dynamically. Take a look to getRowHeight function, it's works for any rows (full-width too):
public getRowHeight: (
params: RowHeightParams
) => number | undefined | null = function (params) {
if (params.node && params.node.detail) {
var offset = 80;
var allDetailRowHeight =
params.data.callRecords.length *
params.api.getSizesForCurrentTheme().rowHeight;
var gridSizes = params.api.getSizesForCurrentTheme();
return (
allDetailRowHeight +
((gridSizes && gridSizes.headerHeight) || 0) +
offset
);
}
};
Here is the solution I ended up with, though I like #LennyLip's answer as well. It uses some ideas from Text Wrapping in ag-Grid Column Headers & Cells.
There were two parts to the problem - 1) calculating the height, and 2) knowing when to calculate the height.
1) Calculating the Height
I updated the footnote's Cell Renderer to add an ID to each footnote text node, and used it in the function below.
const footnoteRowHeightSetter = function(params): void {
const footnoteCells = document.querySelectorAll('.footnote .footnote-text');
const footnoteRowNodes = [];
params.api.forEachNode(row => {
if (row.data.dataType === 'footnote') { // Test to see if it's a footnote
footnoteRowNodes.push(row);
}
});
if (footnoteCells.length > 0 && footnoteRowNodes.length > 0) {
footnoteRowNodes.forEach(rowNode => {
const cellId = 'footnote_' + rowNode.data.id;
const cell = _.find(footnoteCells, node => node.id === cellId);
const height = cell.clientHeight;
rowNode.setRowHeight(height);
});
params.api.onRowHeightChanged();
}
};
To summarize, the function gets all HTML nodes in the DOM that are footnote text nodes. It then gets all of the table's row nodes that are footnotes. It goes through those row nodes, matching each up with its DOM text. It uses the clientHeight property of the text node and sets the row node height to that value. Finally, it calls the api.onRowHeightChanged() function to let the table know it should reposition and draw the rows.
Knowing when to calculate the height
When I set the gridOptions.getRowHeight property to the function above, it didn't work. When the function fires, the footnote rows hadn't yet been rendered, so it was unable to get the clientHeight for the text nodes since they didn't exist.
Instead, I triggered the function using these event handlers in gridOptions.
onFirstDataRendered: footnoteRowHeightSetter,
onBodyScrollEnd: footnoteRowHeightSetter,
onGridSizeChanged: footnoteRowHeightSetter,
onFirstDataRendered covers the case where footnotes are on screen when the grid first renders (short table).
onBodyScrollEnd covers the case where footnotes aren't on screen at first but the user scrolls to see them.
onGridSizeChanged covers the case of grid resizing that alters the wrapping and height of the footnote text.
This is what worked for me. I like #LennyLip's answer and looking more into it before I select an answer.

Echart bind different click event handler for different part of rich-text of xAxis.axisLabel in?

I need to bind click event handler for the icon in the red rectangle zone,bind different click event handler for the blue rectangle zone.
right now ,i have no idea how to make it work, any help will be appreciate
example and codes
I figure out an solution.
You can add an icon dom after the label by manual, like below codes.
var myChart = echarts.init(document.getElementById('main'));
var option = {
// your options
};
const parent = myChart.getDom().parentElement;
const xPixel = myChart.convertToPixel({ xAxisIndex: 0 }, 2) // to get the x postion of target category
var div = document.createElement('img')
div.style = `position: absolute;top: 366px;height: 12px;left:${xPixel + 2 * 14}px` // 2 * 14 is in order to correct the left
div.src = 'image path'
div.addEventListener('click', () => {})
if (parent) parent.appendChild(div)
You can change top or left to correct the icon position.
If somebody have greater solution, plz let me know.

Alignment in Flex table

How can I get the flex table (flex3) to align at the top in this Ui?
function doGet(e) {
var app = UiApp.createApplication();
var flex1 = app.createFlexTable().setBorderWidth(1);
var flex2 = app.createFlexTable().setBorderWidth(1).setWidget(0, 0, app.createLabel('flex2'))
.setWidget(1, 0, app.createTextArea().setHeight(400).setText('Text area in flex2'));
var flex3 = app.createFlexTable().setBorderWidth(1).setWidget(0, 0, app.createLabel('flex3'));
flex1.setWidget(0, 0, flex2).setWidget(0, 1, flex3);
app.add(flex1);
return app;
}
Was expecting...
var flex1 = app.createFlexTable().setBorderWidth(1).setStyleAttribute('vertical-align', 'top');
or
var flex1 = app.createFlexTable().setBorderWidth(1).setColumnStyleAttribute(1, 'vertical-align', 'top');
to work.
Also, using a flow panel instead of a flex for the root didn't work as expected either. That stacked the 2 flex vertically and not left to right.
Adding this line towards the bottom did the trick for me -
flex1.setStyleAttribute(0, 1, 'vertical-align', 'top');
Not sure why the global set style or set column style didn't work. However, setting it on a specific row/column seem to work. Let me know.
This might have to end up on the Issue Tracker, please check there and log an issue.

Table shows extra blank columns at the end

I am using jface tableViewer.When table has no data in it ,it shows all columns correctly But when Data gets added to the table it shows extra blank space or column at the end of the table.
I am using TreeViewer + TreeViewerColumn and had this problem too, this workaround might work for your TableViewer too: Programmatically set the size of the last column on parent resize:
treeViewer.getTree().addControlListener(new ControlAdapter() {
public void controlResized(ControlEvent e) {
packAndFillLastColumn();
}
});
where the action is in
// Resize last column in tree viewer so that it fills the client area completely if extra space.
protected void packAndFillLastColumn() {
Tree tree = treeViewer.getTree();
int columnsWidth = 0;
for (int i = 0; i < tree.getColumnCount() - 1; i++) {
columnsWidth += tree.getColumn(i).getWidth();
}
TreeColumn lastColumn = tree.getColumn(tree.getColumnCount() - 1);
lastColumn.pack();
Rectangle area = tree.getClientArea();
Point preferredSize = tree.computeSize(SWT.DEFAULT, SWT.DEFAULT);
int width = area.width - 2*tree.getBorderWidth();
if (preferredSize.y > area.height + tree.getHeaderHeight()) {
// Subtract the scrollbar width from the total column width
// if a vertical scrollbar will be required
Point vBarSize = tree.getVerticalBar().getSize();
width -= vBarSize.x;
}
// last column is packed, so that is the minimum. If more space is available, add it.
if(lastColumn.getWidth() < width - columnsWidth) {
lastColumn.setWidth(width - columnsWidth);
}
}
Works well for me - you might want to set column resizable to false ;-). This can also be called when data in the last column changes (introducting / removing vertical scroll bar).
Thanks Thomas. Your idea worked for me as well, though I was using TableViewer and TableColumn.
Quoting my code so that others can take some hints.
`public void controlResized(ControlEvent e) {
if ( listOfTableColumns.size() != colProportions.length )
{
logger.warn( "Number of columns passed and size of column proportions array are different. " +
"Columns resizing shall not be effective on GUI window resizing" );
return;
}
Rectangle area = tableBaseComposite.getClientArea();
Point size = theTable.computeSize(SWT.DEFAULT, SWT.DEFAULT);
ScrollBar vBar = theTable.getVerticalBar();
int width = area.width - theTable.computeTrim(0,0,0,0).width - vBar.getSize().x;
if (size.y > area.height + theTable.getHeaderHeight()) {
// Subtract the scrollbar width from the total column width
// if a vertical scrollbar will be required
Point vBarSize = vBar.getSize();
width -= vBarSize.x;
}
Point oldSize = theTable.getSize();
if (oldSize.x > area.width) {
// table is getting smaller so make the columns
// smaller first and then resize the table to
// match the client area width
int index = 0 ;
for ( Iterator<TableColumn> iterator = listOfTableColumns.iterator(); iterator.hasNext(); )
{
TableColumn column = iterator.next();
column.setWidth( (int) numberFromPercentage( width, colProportions[index++] ) );
}
listOfTableColumns.get( listOfTableColumns.size() - 1).pack();
theTable.setSize(area.width, area.height);
} else {
// table is getting bigger so make the table
// bigger first and then make the columns wider
// to match the client area width
int index = 0;
theTable.setSize(area.width, area.height);
for ( Iterator<TableColumn> iterator = listOfTableColumns.iterator(); iterator.hasNext(); )
{
TableColumn column = iterator.next();
column.setWidth( (int) numberFromPercentage( width, colProportions[index++] ) );
}
listOfTableColumns.get( listOfTableColumns.size() - 1).pack();
}
}`
No need for complicated hacks to remove the extra unwanted column space at the end...
Just create a columnLayout:
TableColumnLayout columnLayout = new TableColumnLayout();
and then set it to each of your columns:
columnLayout.setColumnData(YOUR_VIEWER_COLUMN1.getColumn(), new ColumnPixelData(200));
columnLayout.setColumnData(YOUR_VIEWER_COLUMN2.getColumn(), new ColumnWeightData(200, 100));
Finally, set the layout on your parent composite:
parent.setLayout(columnLayout);
Full sample:
public void createPartControl(Composite parent) {
TableViewer viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
TableViewerColumn keyColumn = new TableViewerColumn(viewer, SWT.LEFT);
TableViewerColumn valueColumn = new TableViewerColumn(viewer, SWT.LEFT);
TableColumnLayout columnLayout = new TableColumnLayout();
columnLayout.setColumnData(keyColumn.getColumn(), new ColumnPixelData(200));
columnLayout.setColumnData(valueColumn.getColumn(), new ColumnWeightData(200, 100));
parent.setLayout(columnLayout);
}
Just guessing: maybe your columns do not get resized to fill all the table?
How do you set the widths of columns?
Consider using TableColumnLayout for the table container.
On windows, you will always get an extra column/row if the net width of all the columns that has been set up is less than the dimension of the table. So its always good to make your columns fit your table, also there is some space left for scroll bars, though I am not very sure about this, but its always better to specify whether you want vertical or horizontal scroll bars.
I used the packAndFillLastColumn() method and it worked for me. But I found one issue with it. My table was created with a border. After using the packAndFillLastColumn() method the border for the row no longer exists. I used the setLinesVisible(true) method within the packAndFillLastColumn() method but still that does not work.
So simple! Just remove this line in your table commands inside the createContents function:
table.getColumn(i).pack();
Good-luck
As a workaround use :
-For Column
use TableColumnLayout for the treeViewer's composite and set appropriate column data for each column using:
"tableColumnLayout.setColumnData(column,new ColumnWeightData(...as per your requirement));"
-For Row
Set GridData to the treeViewer's composite and provide height hint using
"gridData.heightHint = table.getItemHeight()*numberOfVisibleRows"
I found eclipse has marked it as WONTFIX.. so can not do much to remove this space..We have tp live with it...:)
To the end column we need to set the setWidth to window size or shell-size, parent-shell size like 1500,5000
final TableViewerColumn viewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
final TableColumn column = viewerColumn.getColumn();
column.setText(title);
column.setResizable(true);
column.setMoveable(true);
//set the setWidth size upto shell size or set upto to some size like 1000,1500,2000,5000
col.setWidth(comp.getShell().getSize().x); // or col.setWidth(1500) ;
return viewerColumn;

JavaScript Mouse position over an element (code not working)

I want to display the mouse position when its inside an element.. heres the code:
Mouse Events Example
function GetMousePositionInElement(ev, element)
{
var osx = element.offsetX;
var osy = element.offsetY;
var bottom = osy + element.height();
var x = ev.pageX - osx;
var y = bottom - ev.pageY;
return { x: x, y: y, y_fromTop: element.height() - y };
}
function handleEvent(oEvent) {
var oTextbox = document.getElementById("txt1");
var elem = document.getElementById("div1");
var xp = GetMousePositionInElement(oEvent, elem).x;
var yp = GetMousePositionInElement(oEvent, elem).y;
oTextbox.value += "\n x = " + xp + "y= " + yp;
}
Use your mouse to click and double click the red square.
div style="width: 100px; height: 100px; background-color: red"
onmouseover="handleEvent(event)"
id="div1"> /div
textarea id="txt1" rows="15" cols="50"> /textarea>
There is a problem in the code. Mouse position is not displayed inside the texArea. What changes do i have to make for the code to work and work correctly? (of-cource not all of the code is displayed and i removed some of the < and > inoder to show you some parts of the code that are not displayed otherwise but the code syntax is correct, thats not the problem)
Thank you.
var osy = element.offsetY;
There's no such property as offsetY. You may be thinking of offsetTop. However note the offsetLeft/​Top values are relative to the offsetParent not the page. If you want page-relative co-ordinates you would need to loop through offsetParents, or, since you seem to be including jQuery, call its offset function that does just that:
var offset= $(element).offset();
var osx= offset[0], osy= offset[1];
var bottom = osy + element.height();
element is a DOM HTMLDivElement object, not a jQuery wrapper object, so it doesn't have the height() method. Either add the wrapper:
var bottom= osy+$(element).height();
or use the equivalent DOM method:
var bottom= osy+element.offsetHeight;
var y = bottom - ev.pageY;
Note pageY is not part of the DOM Events standard and also not available in IE. You can calculate it by using the standard clientY property and adjusting for the page's scrollTop. Again, jQuery does this for you, adding the Firefox pageY extension to all browsers, when you use its own methods to bind your event handler:
$('#div1').mouseover(handleEvent);
instead of the inline onmouseover=... event handler attribute.