近来在写idea插件,需要用到界面,只能使用swing。于是开始踩坑……
需求
解析依赖文件,展示依赖的版本信息和更新时间,用户发现依赖有问题可以自己更新。由于一个JLabel不够用,默认的DefaultTreeCellRenderer
就不够用了,需要开始研究。
第一个坑
DefaultTreeCellRenderer
是继承的JLabel
和TreeCellRenderer
,那么我新写一个继承JComponent
和TreeCellRenderer
的类不就可以了?但是事实是不行,或者说很麻烦。UI相关的资源和配置需要使用sun.swing.DefaultLookup
这个类进行获取,DefaultTreeCellRenderer
在javax.swing.tree
包下,可以访问,但是我们不行,sun.swing.DefaultLookup
这个类并没有公开。直接引用会出现Symbol is declared in module 'java.desktop' which does not export package 'sun.swing'
错误。所以,我们必须使用原来的DefaultTreeCellRenderer
类。
第二个坑
JTree
本质是调用TreeCellRenderer
的getTreeCellRendererComponent
方法,然后一行行画出来的,所以只需要构造一个TreeCellRenderer
类就够了。每一条数据都会执行一遍,然后画到JTree
控件里面去,事件处理也需要注册在JTree
上面。也因此,在自定义TreeCellRenderer
里面添加交互控件,比如按钮,是无效的。如果需要进行交互,最好用右键菜单(有个editorCellRenderer
不确定行不行,没试过,待尝试)。
第三个坑
getTreeCellRendererComponent
方法的value是包装后的MutableTreeNode
,不是userObject
。需要进行转换才能拿到传进去的数据。
示例
package me.small.vision.window
import me.small.vision.data.InfoPO
import java.awt.BorderLayout
import java.awt.Component
import javax.swing.ImageIcon
import javax.swing.JComponent
import javax.swing.JLabel
import javax.swing.JTree
import javax.swing.tree.DefaultMutableTreeNode
import javax.swing.tree.DefaultTreeCellRenderer
import javax.swing.tree.TreeCellRenderer
class MyTreeCellRenderer : JComponent(), TreeCellRenderer {
private var father: DefaultTreeCellRenderer = DefaultTreeCellRenderer()
init {
father.leafIcon = ImageIcon(this.javaClass.classLoader.getResource("leaf.png"))
layout = BorderLayout()
add(JLabel("time"), BorderLayout.EAST)
add(JLabel("info"), BorderLayout.WEST)
}
override fun getTreeCellRendererComponent(
tree: JTree,
value: Any,
selected: Boolean,
expanded: Boolean,
leaf: Boolean,
row: Int,
hasFocus: Boolean
): Component {
value as DefaultMutableTreeNode
remove(1)
if (value.userObject is InfoPO) {
val data = value.userObject!! as InfoPO
(components[0] as JLabel).text = data.time
add(
father.getTreeCellRendererComponent(
tree,
data.name,
selected,
expanded,
leaf,
row,
hasFocus
), BorderLayout.WEST
)
} else {
(components[0] as JLabel).text = ""
add(
father.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus),
BorderLayout.WEST
)
}
return this
}
}
这里有个小坑,components
是私有属性component
的引用,直接修改components[1]
是不行的,必须删了然后添加。这样渲染出来的效果,就是左边是依赖名称,右边是更新时间,清晰明了。
网友评论