So I am a little confused with how to set the css of an individual row in my Datagrid (which as i understand it can use everything the cellTable can use).
First I have a double click and single click handler which do get correctly called in 'onCellPreview'(had to remove selectionModel for this to work). I then can get the row number through event.getIndex().
Next is where I fail in attempt to set the CSS for the selected row, my code:
int Row= event.getIndex();
myDataTable.setRowStyles(new RowStyles<String[]>(){
#Override
public String getStyleNames(String [] rowObject, int theRow){
if (row== theRow){
return "myDataGridSelectedRow";
}
else
return "myDataGrid";
}
});
However I don't understand how this is supposed to work (which is perhaps why I can't get it to work)
How does getStyleNames() get called? It just steps over it in my debugger.
where should the setRowStyles method call be located in my code?
I suppose for this to work properly i must remove the call
myDataTable.setStyleName("myDataGrid");
There is also a pre-existing css class in my DataGridOverride.css(which is different from the main css file where "myDataGrid" is located). The class is
".dataGridSelectedRowCell" and has a background color set (uses !important) but it does not work.
This method setRowStyles() is called only when a table is rendered.
You can set a style dynamically this way:
myDataTable.getRowElement(i).getStyle()...
or
myDataTable.getRowElement(i).setClassName("myDataGridSelectedRow");
You do not need to remove style name from your grid.
EDIT:
An alternative approach is to override the standard DataGrid CSS Resource:
How do I style a gwt 2.1 CellTables headers?
I would recommend this approach if you want to make many changes to default GWT DataGrid styles.
Related
I am building a JTreeTable. I found some starter code and have come pretty far. In the end my goal is to be able to have different data at different levels like a hierarchical list.
Currently, I have it working with data at different levels. However, I am running up against a wall when it comes to changing the columns as a next goal. From where I currently stand I have 3 more milestones:
Show different set of columns for different levels
Ability to adjust column widths for different levels
Ensure the JTree part of the table always stays to left
I am getting close to closing out this task but again stuck at the first of these 3.
Since creating a JTreeTable is complex, the minimum example leverages several class listed below in the image:
I am happy to post the code to any of those classes but I also did not want clog the question with useless code. First let me show the functionality I want.
The first image is when the top level is selected and the second image is when the second level is selected. Notice how the columns are different. That is what I want to happen in my application.
Top level selected:
Second level selected:
So one way I tried to solve this problem, is when the list selection is changed inside this section of code:
ListSelectionListener listener = (ListSelectionEvent e) -> {
TreeTableModelAdapter adapter = (TreeTableModelAdapter) JTreeTable.this.getModel();
//Need to see why this breaks.
JTreeTable.this.getTableHeader().setColumnModel(adapter.getColumnModel());
};
this.getSelectionModel().addListSelectionListener(listener);
This code is in the initialization of the JTreeTable. I have tried setting the column model on both the TableHeader and the table as well. Below is what happens then when I select a row:
The columns just disappear on me. The creation of the column model is happening in the TreeTableModelAdapter class with the following method:
public TableColumnModel getColumnModel(){
DefaultTableColumnModel model = new DefaultTableColumnModel();
for(int i=0;i<getColumnCount();i++){
TableColumn column = new TableColumn();
column.setIdentifier(getColumnName(i));
model.addColumn(column);
}
return model;
}
Any direction would be very helpful. Again happy to post any code you think could be helpful to answer the question. Just put a comment in and I will add it right away.
I will add the milestones as I find them in case this helps others, but for now this question is answered.
Milestone 1
I was actually able to solve the first milestone. The key is to trigger the creation of the columns of the column model, not to create a new column model. Below is the code for when the row selection is changed:
//Change columns depending on row
ListSelectionListener listener = (ListSelectionEvent e) -> {
createDefaultColumnsFromModel();
};
this.getSelectionModel().addListSelectionListener(listener);
This code creates the columns based on the row selected in the JTree part of the JTreeTable. The TreeTableModelAdapter implements the getColumnCount() and getColumnName() methods by also passing the selected row in the JTree to the JTreeTableModel so that the columns and their names are dynamically retrieved based on a particular node in the JTree. The key for this for me was trigger those to be called again to update the JTreeTable.
Milestone 2
Adjusting column widths based on the data level proved to be much more difficult than I had originally anticipated. In order to retain the cells state when the column model changed I had to disconnect the painting of the cells from it. This is a hairy process because this is done inside BasicTableUI and the method that gets the rectangle of the cell is private. So I had to subclass it, overload the paint() method and create my own methods that get called inside the paint method. There was a lot of copy pasting so that I could call normally private methods. I just renamed them and referenced these methods instead. The way the ui class was designed did not make it very flexible. Below is 2 images where I am selecting different levels and the columns are obviously different widths at different levels.
Milestone 3
I was able to make this work by keeping track of the view in the model. This seems very dirty to me as the model should separated from the view. Since the tree column's class is unique, I just returned the right class if that column was the first in the view.
The one problem I have with this technique is that I get unexpected behavior where the value returned is not consistent. I attempted to resolve this by overriding JTree.covertValueToText(). Since a JTree only expects 1 value and depending on the sequence of columns in the view this value could change. So in overriding this method I check the stored index for the JTree column's value. Again this causes the unexpected behavior. I will update the post if I find the fix.
When I click on a row, the entire row color changes as expected. However the cell that the mouse is over changes to a different color than the rest of the row. I am trying to prevent the cell from changing to a color that is different from the rest of the row.
I am trying to figure out where the cell selection color is getting set and how to remove that (let the cell selection use the cells current background color).
I have unsuccessfully tried things like modifying the CellConfigAttribute or unregistering it via:
getNatTable().getConfigRegistry().
unregisterConfigAttribute(CellConfigAttributes.CELL_STYLE);
but no luck. I have no clue how to iterate over all the styles in order and see where this is generated from. I would have liked to see an existing method similar to:
List<ConfigAttribute<IStyle>> list = getNatTable().getConfigRegistry().
getConfigAttributesInOrder();
Unfortunately all I see is something like this, which I don't find useful for my situation:
List<String> strings = getNatTable().getConfigRegistry().
getDisplayModeOrdering().getDisplayModeOrdering("SELECT");
I have read the documentation which has some general advice but seen no explicit code samples showing how to do this. So, show do I determine where the cell is getting modified and how do I prevent it?
The code I am using for complete row selection is:
public void foo() {
final SelectionLayer selectionLayer = glazedListsGridLayer.
getBodyLayerStack().getSelectionLayer();
final RowOnlySelectionConfiguration<T> selectionConfig =
new RowOnlySelectionConfiguration<>();
selectionLayer.addConfiguration(selectionConfig);
getNatTable().addConfiguration(new RowOnlySelectionBindings());
}
You are talking about the selection anchor. And the only thing you have to do is to register the same style for DisplayMode.SELECT and label SelectionStyleLabels.SELECTION_ANCHOR_STYLE that you register for only DisplayMode.SELECT. The different style is registered in DefaultSelectionStyleConfiguration
I want to do plain UI testing (i.e., not using SWTBot or other UI test frameworks) of NatTable contents.
My approach is to create a shell, add my custom NatTable and then access the cell and check its contents (data value, config label etc.):
// Note: this is Xtend code
#Before
def void setup()
{
shell = new Shell(Display.getCurrent)
shell.layout = new FillLayout
parent = new Composite(shell, SWT.NONE)
parent.layout = new GridLayout
fixture = new MyNatTableViewer(parent) // this is my custom nattable impl under test
shell.pack
shell.visible = true
}
#Test
def void testLabel()
{
assertCellLabel(2, 2, "test-label");
}
def assertCellLabel(int row, int col, String expected)
{
val labels = parameterTable.getCellByPosition(col, row)?.configLabels
assertThat(labels).describedAs("Labels for row " + row + " col " + col).isNotNull
assertThat(labels.labels).describedAs("Labels for row " + row + " col " + col).contains(expected)
}
To test my other components it was enough to just create the shell and the parent composite; packing and setting visible was not required for my tests to work.
Yet, with NatTable, getCellByPosition() returns null if the cell is not visible - so I added the code to pack and set the shell visible. This works for small tables (with 2 rows and a few columns).
Sadly, it does not work for large tables. I suspect this is because the viewport layer does not create cells which are not in the visible area (which is, I know, the strength of NatTable - that it only creates the required structures on demand). This is, of course, desired for normal runtime behavior.
But is there a(nother) way to get the cell in a guaranteed way (in other words, can I make the NatTable/ViewportLayer believe that the cell is visible so I don't get null as long as the cell exists content-wise?)
I could, of course, test my label accumulators, data providers etc. directly, but I wanted to approach this more from a black-box point of view here.
That question is contradictory in itself. You are asking for a black box approach for testing NatTable, but you want to change the behavior of NatTable on testing. That is not a black box approach!
If you really want to test with a black box approach, you need to ensure that the cell is rendered. This can be done by triggering scrolling, e.g. by executing the ShowCellInViewportCommand. That is the real black box approach, because returning null for a non-visible cell is the correct result.
If you need something in between a real black box approach and an approach that makes use of internal knowledge (which you are asking for) you have to ways to get there.
Operate on a layer below the ViewportLayer. Typically the SelectionLayer can be used. But of course this doesn't need to mean anything, because the layer stack can differ from setup to setup. The ViewportLayer is the one that introduces the virtual nature to a NatTable and the scrolling ability. It avoids the access to the underlying layers. So asking one of these will return the value you expect.
Disable the ViewportLayer by executing the TurnViewportOffCommand. This is basically a hack and could trigger additional things in the back that you might not want. But I have seen that suggestion in other contexts and therefore want to name it here. I don't suggest to use it anyway!
Note that both approaches are more like hacks when we are talking about black box testing, because you are making assumptions to the composition. They can not be applied in general because of the various configuration abilities.
Regarding the hidden question about why you need to set the Shell visible. Well basically because the SWT events for painting and resizing need to be triggered in order to start the size calculations and printing of NatTable correctly according to the Shell state. In our examples (which are also plain SWT) we call Shell#open().
And as a last comment on your implementation, I don't understand why you are sub-classing NatTable. Our API was never intended to do that. I suppose you do this to do some static pre-configuration e.g. the layer stack. But personally I don't like that approach. Everytime someone extends our classes to override some internal methods it ends up in questions or bug reports because the behavior changes. But I think that is generally an issue of an open API to give developers the most possible flexibility on customization.
I am also trying to read data from invisible cells of nattable. I am trying to use ShowCellInViewportCommand as follows:
widget.doCommand(new ShowCellInViewportCommand(gridlayer.getBodyLayer(), column, row));
//where row is say 50 and column is 20 and the cell is invisible.
I also tried,
widget.doCommand(new ShowRowInViewportCommand(widget.getLayer(), row));
//here the default value given by nattable.getLayer is passed
widget corrosponds to nattable instance.
After the call, nothing happens in UI. The cell does not get displayed.
Do I need to do anything else?
How should I go to read invisible cells of nattable.
I'm having a problem where zk 3.6.3 is rendering a second <tbody> tag for a Listbox. Actually the first rendered <tbody> tag is the one that is making me problems. It has it's css style set to visibility:hidden;height:0px and Opera 12 and IE 11 are rendering a large white empty space for it. So in the browser I see the table header, this empty space and then the actual rows of the listbox.
The problematic code for zkoss rendering is contained in org.zkoss.zkmax.zul.render.ListboxDefault in lines 53-63.
How can I prevent zkoss or browsers from rendering this empty space?
Well, there is always a solution and maybe the "hacking" solution is the best here :
Class overriding of that class.
Create that package and create that class (exactly the same package and classname).
Copy the code from your link to your class.
Change the code, I'll suggest try to remove the complete if. => See what result it gives (test al your listboxes!)
When you ever think of upgrading ZK version : Don't forget to remove or update the class !!!
If removing doesn't help, try to change the style,...
On the other hand, if updating ZK version is possible, you should try that.
The version you use is old, and doesn't support newer browsers.
The first tbody contains the list header (no, I don't know why they don't use thead for this). If you don't add one to the list, the CSS visibility:hidden;height:0px should make it invisible on the screen and that works for me.
My guess is that somewhere in the app, you have CSS rules which override this style. So the next step is to fire up the web developer tools and check which CSS styles are actually applied.
Alternatively, you can give the list box a custom class setSclass("hiddenheader") and then use CSS like this:
table.hiddenheader tbody:first-child { display: none; }
(note: I didn't test this; ZK might add some prefix to the styles so you might have to adjust the code but the example should get you started).
I want to implement some functionality--there are multiple rows with a checkbox at the starting in a jsp file in struts2.1 framework. If the checkbox is checked then at the same instant the color of that row should change, like it is selected. How should I implement this?
I recommend the jQuery plugin – tableRowCheckboxToggle (demo)
I agree with lschin; use a canned solution.
That said, you could also do it "manually" using jQuery or similar. Attach an onclick handler to each checkbox that sets a CSS style on its containing row.
Simplistically, use the checkbox's onclick attribute to provide a click handler and an ID that can be used to find the containing row.
Less obtrusively (and arguably better all around), find the row containing the checkbox by walking up the DOM (in jQuery, something like inside the attached click handler: $(this).parents("tr")[0]) and don't worry about throwing around a lot of IDs.