JTable中JEditorPane的超链接 [英] hyperlinks in JEditorPane in a JTable

查看:129
本文介绍了JTable中JEditorPane的超链接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发誓...我希望这是我必须要问的最后一个问题,但我即将发疯。



我有一个使用自定义TableCellRenderer的JTable,该自定义TableCellRenderer使用JEditorPane在JTable的单个单元格中显示html。我如何处理单击JEditorPane中显示的链接?



我知道HyperlinkListener,但没有鼠标事件通过JTable传递给EditorPane,以处理任何HyperlinkEvents。



如何在JTable中的JEditorPane中处理超链接?

解决方案

EditorPane没有收到任何事件,因为从TableCellRenderer返回的组件只允许显示,并且不拦截事件,使其几乎与图像相同,没有任何行为被允许。因此,即使听众注册了,返回的组件也不会意识到任何事件。解决方法是在JTable上注册一个MouseListener,并拦截所有相关的事件。

这是我过去创建的一些类,用于允许JButton转换在JTable中工作,但是您应该能够重用这些大部分内容来解决问题太。我为每个需要它的单元都有一个单独的JButton。这样,这个ActiveJComponentTableMouseListener可以处理鼠标事件发生在哪个单元格中,并将事件分派给相应的组件。这是ActiveJComponentTableCellRenderer的工作,通过一个Map来跟踪组件。



知道它什么时候已经被触发事件足够聪明,所以你没有积压的冗余事件。对超文本实现这一点不应该有所不同,并且您可能仍然需要翻阅。这里是类

  public class ActiveJComponentTableMouseListener extends MouseAdapter implements MouseMotionListener {

private JTable table;
private JComponent oldComponent = null;
private TableCell oldTableCell = new TableCell();

public ActiveJComponentTableMouseListener(JTable table){
this.table = table;

$ b @Override
public void mouseMoved(MouseEvent e){
TableCell cell = new TableCell(getRow(e),getColumn(e));

if(alreadyVisited(cell)){
return;
}
save(cell);

if(oldComponent!= null){
dispatchEvent(createMouseEvent(e,MouseEvent.MOUSE_EXITED),oldComponent);
oldComponent = null;
}

JComponent component = getComponent(cell);
if(component == null){
return;
}
dispatchEvent(createMouseEvent(e,MouseEvent.MOUSE_ENTERED),component);
saveComponent(component);
save(cell);

$ b @Override
public void mouseExited(MouseEvent e){
TableCell cell = new TableCell(getRow(e),getColumn(e));

if(alreadyVisited(cell)){
return;
}
if(oldComponent!= null){
dispatchEvent(createMouseEvent(e,MouseEvent.MOUSE_EXITED),oldComponent);
oldComponent = null;
}
}

@Override
public void mouseEntered(MouseEvent e){
forwardEventToComponent(e);


private void forwardEventToComponent(MouseEvent e){
TableCell cell = new TableCell(getRow(e),getColumn(e));
save(cell);
JComponent component = getComponent(cell);
if(component == null){
return;
}
dispatchEvent(e,component);
saveComponent(component);


private void dispatchEvent(MouseEvent componentEvent,JComponent component){
MouseEvent convertedEvent =(MouseEvent)SwingUtilities.convertMouseEvent(table,componentEvent,component);
component.dispatchEvent(convertedEvent);
//这是必要的,这样当一个按钮被按下并释放
//它就会被正确渲染。否则,该按钮在释放后可能仍会出现
// //。
table.repaint();


private JComponent getComponent(TableCell cell){
if(rowOrColumnInvalid(cell)){
return null;
}
TableCellRenderer renderer = table.getCellRenderer(cell.row,cell.column);

if(!(renderer instanceof ActiveJComponentTableCellRenderer)){
return null;
}
ActiveJComponentTableCellRenderer activeComponentRenderer =(ActiveJComponentTableCellRenderer)renderer;

返回activeComponentRenderer.getComponent(cell);


private int getColumn(MouseEvent e){
TableColumnModel columnModel = table.getColumnModel();
int column = columnModel.getColumnIndexAtX(e.getX());
返回列;
}

private int getRow(MouseEvent e){
int row = e.getY()/ table.getRowHeight();
返回行;


私有布尔rowInvalid(int row){
返回行> = table.getRowCount()||行< 0;
}

private boolean rowOrColumnInvalid(TableCell cell){
return rowInvalid(cell.row)|| columnInvalid(cell.column);
}

private boolean alreadyVisited(TableCell cell){
return oldTableCell.equals(cell);


private boolean columnInvalid(int column){
return column> = table.getColumnCount()||列< 0;

$ b $ private MouseEvent createMouseEvent(MouseEvent e,int eventID){
return new MouseEvent((Component)e.getSource(),eventID,e.getWhen(),e .getModifiers(),e.​​getX(),e.​​getY(),e.​​getClickCount(),e.​​isPopupTrigger(),e.​​getButton());
}
private void save(TableCell cell){
oldTableCell = cell;
}

private void saveComponent(JComponent component){
oldComponent = component;
}}


public class TableCell {

public int row;
public int column;
$ b $ public TableCell(){
}

public TableCell(int row,int column){
this.row = row;
this.column = column;

$ b @Override
public boolean equals(Object obj){
if(obj == null){
return false;
}
if(getClass()!= obj.getClass()){
return false;
}
final TableCell other =(TableCell)obj;
if(this.row!= other.row){
return false;
}
if(this.column!= other.column){
return false;
}
返回true;
}

@Override
public int hashCode(){
int hash = 7;
hash = 67 * hash + this.row;
hash = 67 * hash + this.column;
返回散列;
}}

public class ActiveJComponentTableCellRenderer< T extends JComponent>扩展AbstractCellEditor实现TableCellEditor,TableCellRenderer {

private Map< TableCell,T>组件;
private JComponentFactory< T>厂;
$ b $ public ActiveJComponentTableCellRenderer(){
this.components = new HashMap< TableCell,T>();

$ b $ public ActiveJComponentTableCellRenderer(JComponentFactory< T> factory){
this();
this.factory = factory;

$ b $ public T getComponent(TableCell key){
T component = components.get(key);
if(component == null&& factory!= null){
// lazy-load component
component = factory.build();
initialiseComponent(component);
components.put(key,component);
}
返回组件;

$ b $ **
*重写此方法以提供自定义组件初始化代码
* @param组件从getComponent(cell)
* /
保护无效初始化组件(T组件){
}
$ b $ @覆盖
公共组件getTableCellRendererComponent(JTable表,对象值,布尔isSelected,布尔hasFocus,int行,int列){
return getComponent(new TableCell(row,column));
}

@Override
public Object getCellEditorValue(){
return null;

$ b @Override
public Component getTableCellEditorComponent(JTable table,Object value,boolean isSelected,int row,int column){
return getComponent(new TableCell(row ,列));
}

public void setComponentFactory(JComponentFactory factory){
this.factory = factory;
}}

public interface JComponentFactory< T extends JComponent> {
T build();

$ / code>

要使用它,您需要将侦听器注册为鼠标和运动侦听器放在桌子上,然后在适当的单元格上注册渲染器。如果你想拦截actionPerformed类型的事件,可以这样重写ActiveJComponentTableCellRenderer.initialiseComponent():

  protected void initialiseComponent(T component){ 
component.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
stopCellEditing();
}
}) ;
}


I swear... i hope this is the last question I have to ask like this, but I'm about to go crazy.

I've got a JTable using a custom TableCellRenderer which uses a JEditorPane to display html in the individual cells of the JTable. How do I process clicking on the links displayed in the JEditorPane?

I know about HyperlinkListener but no mouse events get through the JTable to the EditorPane for any HyperlinkEvents to be processed.

How do I process Hyperlinks in a JEditorPane within a JTable?

解决方案

The EditorPane isn't receiving any events because the component returned from the TableCellRenderer is only allowed to display, and not intercept events, making it pretty much the same as an image, with no behaviour allowed on it. Hence even when listeners are registered, the returned component is never 'aware' of any events. The work-around for this is to register a MouseListener on the JTable, and intercept all relevant events from there.

Here's some classes I created in the past for allowing JButton roll-over to work in a JTable, but you should be able to re-use most of this for your problem too. I had a separate JButton for every cell requiring it. With that, this ActiveJComponentTableMouseListener works out in which cell the mouse event occurs in, and dispatches an event to the corresponding component. It's the job of the ActiveJComponentTableCellRenderer to keep track of the components via a Map.

It's smart enough to know when it's already fired events, so you don't get a backlog of redundant events. Implementing this for hypertext shouldn't be that different, and you may still want roll-over too. Here are the classes

public class ActiveJComponentTableMouseListener extends MouseAdapter implements MouseMotionListener {

private JTable table;
private JComponent oldComponent = null;
private TableCell oldTableCell = new TableCell();

public ActiveJComponentTableMouseListener(JTable table) {
    this.table = table;
}

@Override
public void mouseMoved(MouseEvent e) {
    TableCell cell = new TableCell(getRow(e), getColumn(e));

    if (alreadyVisited(cell)) {
        return;
    }
    save(cell);

    if (oldComponent != null) {
        dispatchEvent(createMouseEvent(e, MouseEvent.MOUSE_EXITED), oldComponent);
        oldComponent = null;
    }

    JComponent component = getComponent(cell);
    if (component == null) {
        return;
    }
    dispatchEvent(createMouseEvent(e, MouseEvent.MOUSE_ENTERED), component);
    saveComponent(component);
    save(cell);
}

@Override
public void mouseExited(MouseEvent e) {
    TableCell cell = new TableCell(getRow(e), getColumn(e));

    if (alreadyVisited(cell)) {
        return;
    }
    if (oldComponent != null) {
        dispatchEvent(createMouseEvent(e, MouseEvent.MOUSE_EXITED), oldComponent);
        oldComponent = null;
    }
}

@Override
public void mouseEntered(MouseEvent e) {
    forwardEventToComponent(e);
}

private void forwardEventToComponent(MouseEvent e) {
    TableCell cell = new TableCell(getRow(e), getColumn(e));
    save(cell);
    JComponent component = getComponent(cell);
    if (component == null) {
        return;
    }
    dispatchEvent(e, component);
    saveComponent(component);
}

private void dispatchEvent(MouseEvent componentEvent, JComponent component) {
    MouseEvent convertedEvent = (MouseEvent) SwingUtilities.convertMouseEvent(table, componentEvent, component);
    component.dispatchEvent(convertedEvent);
    // This is necessary so that when a button is pressed and released
    // it gets rendered properly.  Otherwise, the button may still appear
    // pressed down when it has been released.
    table.repaint();
}

private JComponent getComponent(TableCell cell) {
    if (rowOrColumnInvalid(cell)) {
        return null;
    }
    TableCellRenderer renderer = table.getCellRenderer(cell.row, cell.column);

    if (!(renderer instanceof ActiveJComponentTableCellRenderer)) {
        return null;
    }
    ActiveJComponentTableCellRenderer activeComponentRenderer = (ActiveJComponentTableCellRenderer) renderer;

    return activeComponentRenderer.getComponent(cell);
}

private int getColumn(MouseEvent e) {
    TableColumnModel columnModel = table.getColumnModel();
    int column = columnModel.getColumnIndexAtX(e.getX());
    return column;
}

private int getRow(MouseEvent e) {
    int row = e.getY() / table.getRowHeight();
    return row;
}

private boolean rowInvalid(int row) {
    return row >= table.getRowCount() || row < 0;
}

private boolean rowOrColumnInvalid(TableCell cell) {
    return rowInvalid(cell.row) || columnInvalid(cell.column);
}

private boolean alreadyVisited(TableCell cell) {
    return oldTableCell.equals(cell);
}

private boolean columnInvalid(int column) {
    return column >= table.getColumnCount() || column < 0;
}

private MouseEvent createMouseEvent(MouseEvent e, int eventID) {
    return new MouseEvent((Component) e.getSource(), eventID, e.getWhen(), e.getModifiers(), e.getX(), e.getY(), e.getClickCount(), e.isPopupTrigger(), e.getButton());
}
private void save(TableCell cell) {
    oldTableCell = cell;
}

private void saveComponent(JComponent component) {
    oldComponent = component;
}}


public class TableCell {

public int row;
public int column;

public TableCell() {
}

public TableCell(int row, int column) {
    this.row = row;
    this.column = column;
}

@Override
public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final TableCell other = (TableCell) obj;
    if (this.row != other.row) {
        return false;
    }
    if (this.column != other.column) {
        return false;
    }
    return true;
}

@Override
public int hashCode() {
    int hash = 7;
    hash = 67 * hash + this.row;
    hash = 67 * hash + this.column;
    return hash;
}}

public class ActiveJComponentTableCellRenderer<T extends JComponent> extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {

private Map<TableCell, T> components;
private JComponentFactory<T> factory;

public ActiveJComponentTableCellRenderer() {
    this.components = new HashMap<TableCell, T>();        
}

public ActiveJComponentTableCellRenderer(JComponentFactory<T> factory) {
    this();
    this.factory = factory;
}

public T getComponent(TableCell key) {
    T component = components.get(key);
    if (component == null && factory != null) {
        // lazy-load component
        component = factory.build();
        initialiseComponent(component);
        components.put(key, component);
    }
    return component;
}

/**
 * Override this method to provide custom component initialisation code
 * @param component passed in component from getComponent(cell)
 */
protected void initialiseComponent(T component) {
}

@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    return getComponent(new TableCell(row, column));
}

@Override
public Object getCellEditorValue() {
    return null;
}

@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
    return getComponent(new TableCell(row, column));
}

public void setComponentFactory(JComponentFactory factory) {
    this.factory = factory;
}}

public interface JComponentFactory<T extends JComponent> {
T build();
}

To use it, you want to register the listener to as mouse and motion listener on the table, and register the renderer on the appropriate cells. If you want to intercept actionPerformed type events, override ActiveJComponentTableCellRenderer.initialiseComponent() like so:

protected void initialiseComponent(T component) {
    component.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            stopCellEditing();
        }
    });
}

这篇关于JTable中JEditorPane的超链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆