可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I've got a CellTable with multiple columns in simple TextCell()s. Two of the columns are 'clickable' via the ClickableTextCell() class, but I want to change how they look. What's the easiest way to get the cell contents to resemble an anchor tag, while still using a cell in the table?
I've tried the following:
1. Implement a custom renderer to add anchor tags
2. Scouring Google looking for hints
3. Ignoring 'my library does it you just have to change your entire framework' links
4. Rolling my head across they keyboard
It's funny how annoying this simple change is turning out to be.
My current thought is to implement a custom AnchorCell type which puts in an Anchor widget instead of whatever it does in the other ones, but I'm not sure what all would need to be done.
Any help is appreciated.
回答1:
As an example:
public class MyClickableCellText extends ClickableTextCell {
String style;
public MyClickableCellText()
{
super();
style = "myClickableCellTestStyle";
}
@Override
protected void render(Context context, SafeHtml value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendHtmlConstant("<div class=\""+style+"\">");
sb.append(value);
sb.appendHtmlConstant("</div>");
}
}
public void addStyleName(String style)
{
this.style = style;
}
}
And the style (without the div, because you are hardcoding the style on it):
.myClickableCellTestStyle{
text-decoration:underline;
}
You can even create your own cell by not extending ClickableTextCell but extending AbstractCell (more powerful but need more explanation). Ask me if you need it!
回答2:
Mentioned solution have the problem, these are no links and stylesheets with a:hover and so on doesn't work.
Here is my solution:
private class SellerName {
private final String sellerName;
private final Command cmd;
private SellerName(String displayName, Command cmd) {
this.sellerName = displayName;
this.cmd = cmd;
}
public String getDisplayName() {
return sellerName;
}
public Command getCommand() {
return cmd;
}
};
private class SellerNameCell extends AbstractCell<SellerName> {
public SellerNameCell() {
super("click", "keydown");
}
@Override
public void render(com.google.gwt.cell.client.Cell.Context context, SellerName value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendHtmlConstant("<a href='javascript:;'>");
sb.appendEscaped(value.getDisplayName());
sb.appendHtmlConstant("</a>");
}
}
@Override
public void onBrowserEvent(Context context, Element parent, SellerName value, NativeEvent event, ValueUpdater<SellerName> valueUpdater) {
if (value == null)
return;
super.onBrowserEvent(context, parent, value, event, valueUpdater);
if ("click".equals(event.getType())) {
if (value.getCommand() != null)
value.getCommand().execute();
}
}
};
It creates a real anchorcell which is clickable :)
回答3:
It would seem that your first instinct (implementing a custom renderer) is way easier:
SafeHtmlRenderer<String> anchorRenderer = new AbstractSafeHtmlRenderer<String>()
{
@Override
public SafeHtml render(String object) {
SafeHtmlBuilder sb = new SafeHtmlBuilder();
sb.appendHtmlConstant("<a href=\"javascript:;\">")
.appendEscaped(object).appendHtmlConstant("</a>");
return sb.toSafeHtml();
}
};
And then:
Column<YourThingy, String> anchorCol = new Column<YourThingy, String>(
new ClickableTextCell(anchorRenderer))
{
@Override
public String getValue(YourThingy object) {
return object.toString();
}
};
回答4:
This is what you need:
public class ClickableSafeHtmlCell extends AbstractCell<SafeHtml> {
/**
* Construct a new ClickableSafeHtmlCell.
*/
public ClickableSafeHtmlCell() {
super("click", "keydown");
}
@Override
public void onBrowserEvent(Context context, Element parent, SafeHtml value, NativeEvent event,
ValueUpdater<SafeHtml> valueUpdater) {
super.onBrowserEvent(context, parent, value, event, valueUpdater);
if ("click".equals(event.getType())) {
onEnterKeyDown(context, parent, value, event, valueUpdater);
}
}
@Override
protected void onEnterKeyDown(Context context, Element parent, SafeHtml value,
NativeEvent event, ValueUpdater<SafeHtml> valueUpdater) {
if (valueUpdater != null) {
valueUpdater.update(value);
}
}
@Override
public void render(Context context, SafeHtml value, SafeHtmlBuilder sb) {
if (value != null) {
sb.append(value);
}
}
And then usage:
Column<YourProxy, SafeHtml> nameColumn = new Column<YourProxy, SafeHtml>(
new ClickableSafeHtmlCell()) {
@Override
public SafeHtml getValue(YourProxy object) {
SafeHtmlBuilder sb = new SafeHtmlBuilder();
sb.appendHtmlConstant("<a>");
sb.appendEscaped(object.getName());
sb.appendHtmlConstant("</a>");
return sb.toSafeHtml();
}
};
nameColumn.setFieldUpdater(new FieldUpdater<YourProxy, SafeHtml>() {
@Override
public void update(int index, YourProxy object, SafeHtml value) {
Window.alert("You have clicked: " + object.getName());
}
});
回答5:
This is actually quite simple, but it's amazing how many wrong and convoluted answers there are on Google, and seemingly no correct ones! Anyway, here's the code:
private Column<Object, SafeHtml> getAnchorColumn() {
return new Column<Object, SafeHtml>(new SafeHtmlCell()) {
@Override
public SafeHtml getValue(final Object object) {
Anchor anchor = new Anchor();
anchor.setHref(object.getURL());
anchor.setText(object.getText());
SafeHtmlBuilder sb = new SafeHtmlBuilder();
sb.appendHtmlConstant(anchor.toString());
return sb.toSafeHtml();
}
};
}
Change object to whatever it is you're trying to render in the table then run this method when creating the column, easy!
回答6:
If you take a look to the clickableTextCell html code generated by gwt you will see something like (taken from gwt showcase)
<div style="outline:none;" tabindex="0">Click Robert</div>
So I will recommend u doing something like:
ClickableTextCell cell = new ClickableTextCell();
cell.addStyleName("yourStyle");
and in you style.css do whatever you want.
.yourStyle div{
text-decoration:underline;
}
回答7:
It is essentially a hack to use appendHtmlConstant
. Simply using toString
of the Anchor
or its element or passing a HTML string violates the concept behind SafeHtml
entirely.
In my opinion a proper SafeHtmlTemplates
should be used to tackle unreadable and unsafe string concatenation of HTML. Similar to:
protected interface AnchorTemplate extends SafeHtmlTemplates {
@Template("<a href=\"{0}\">{1}</a>")
SafeHtml anchor(String url, String text);
}
Then you can use GWT.create
on it and interpolate the arguments properly.
Second part is that reading the HTML string of a widget could be optimized out. I was extending AbstractCell
and had this method:
/* do not dare to copy - considered broken */
@Override
public void render(final Context context, final String value, final SafeHtmlBuilder sb) {
final Anchor anchor = new Anchor();
anchor.setText(value);
sb.appendHtmlConstant(anchor.getElement().toString());
}
I just experienced a case where the anchor cell was working fine in superdev mode, but compiling it (probably with more aggressive optimization settings) and then deploying it manually led to an entirely empty cell with no changes in code reproducibly across several systems. Using the template mechanism described above made it work properly (GWT 2.7).
回答8:
First things first - each GWT CellTable Column is just a stack of Cell(s), as our need is to make each Cell look like an anchor which can listen to Click event lets provide ClickableTextCell as argument to Column.
Column<YourObj, String> col = new Column<YourObj, String>(new ClickableTextCell()) {};
2nd - override "render()" method in your Column instance and build your HTML template that you want, here our need is creating an anchor.
@Override
public void render(Context context, YourObj yourObj, SafeHtmlBuilder sb) {
sb.appendHtmlConstant("<a style='text-decoration:underline; cursor: pointer;'>" + yourObj.getX() + "</a>");
}
3rd - as we are using ClickableTextCell, it serves as Click Event source. We need to provide ClickEvent listener, we do that by overriding "onBrowserEvent()" method.
@Override
public void onBrowserEvent(Context context, Element elem, Customer customer, NativeEvent event) {
if ("click".equals(event.getType())) {
Window.alert("ID is : " + customer.getId());
}
}
Complete Code snippet :
Column<YourObj, String> col = new Column<YourObj, String>(new ClickableTextCell()) {
@Override
public String getValue(final YourObj yourObj) {
return yourObj.getX();
}
@Override
public void render(Context context, YourObj yourObj, SafeHtmlBuilder sb) {
sb.appendHtmlConstant("<a style='text-decoration:underline; cursor: pointer;'>" + yourObj.getX() + "</a>");
}
@Override
public void onBrowserEvent(Context context, Element elem, YourObj yourObj, NativeEvent event) {
if ("click".equals(event.getType())) {
Window.alert("ID is : " + yourObj.getId());
}
}
};
cellTable.addColumn(col, "First Name");