- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在使用默认情况下对表进行行条纹的外观。当我放入 JXTreeTable
时,我注意到由于某种原因它没有自动获取行 strip 化。
所以我使用荧光笔提出了一种解决方法,但看起来我遇到了重画故障:
看起来JXTreeTable
只是专门重新绘制文本的边界而不是整个单元格。我一直试图在调试器中捕获此问题以找出原因,但每次我在程序之间切换时,整个窗口都会重新绘制,因此几乎不可能捕获这种情况。
JTable
和 JTree
都表现得很正常。这种外观和感觉是绘制 JTree 的整行(如 Quaqua 和 Synth),所以也许这也与它有关。也许 JXTreeTable 有某种假设,即外观不会绘制树的行?如果是这样,有没有办法解决这个问题?问题不仅仅在于外观和感觉。
代码:
import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.decorator.AbstractHighlighter;
import org.jdesktop.swingx.decorator.ComponentAdapter;
import org.jdesktop.swingx.decorator.Highlighter;
import org.jdesktop.swingx.treetable.DefaultMutableTreeTableNode;
import org.jdesktop.swingx.treetable.DefaultTreeTableModel;
import org.jdesktop.swingx.treetable.TreeTableModel;
import org.trypticon.haqua.HaquaLookAndFeel;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import java.awt.BorderLayout;
import java.awt.Component;
import java.util.Arrays;
public class TreeTableDemo2 implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new TreeTableDemo2());
}
@Override
public void run() {
try {
UIManager.setLookAndFeel(new HaquaLookAndFeel());
} catch (Exception e) {
throw new RuntimeException(e);
}
JFrame frame = new JFrame("Tree Table Demo");
frame.setLayout(new BorderLayout());
frame.add(createPanel(), BorderLayout.CENTER);
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public JPanel createPanel() {
JPanel panel = new JPanel(new BorderLayout());
TreeTableModel treeTableModel = new DummyTreeTableModel();
JXTreeTable treeTable = new FixedTreeTable(treeTableModel);
JScrollPane treeTableScroll = new JScrollPane(treeTable);
panel.add(treeTableScroll, BorderLayout.CENTER);
return panel;
}
private static class FixedTreeTable extends JXTreeTable {
private static final Highlighter oddRowHighlighter = new AbstractHighlighter() {
@Override
protected Component doHighlight(Component component, ComponentAdapter componentAdapter) {
if (componentAdapter.row % 2 != 0 &&
!componentAdapter.isSelected()) {
component.setBackground(UIManager.getColor("Table.alternateRowColor"));
}
return component;
}
};
public FixedTreeTable(TreeTableModel treeModel) {
super(treeModel);
// This hack makes it paint correctly after releasing the mouse, which is not quite good enough.
// getSelectionModel().addListSelectionListener(new ListSelectionListener() {
// @Override
// public void valueChanged(ListSelectionEvent e) {
// Rectangle repaintRange = getCellRect(e.getFirstIndex(), 0, true);
// repaintRange.add(getCellRect(e.getLastIndex(), 0, true));
// repaint(repaintRange);
// }
// });
}
@Override
public void updateUI() {
removeHighlighter(oddRowHighlighter);
super.updateUI();
// JTable does this striping automatically but JXTable's default renderer
// seems to ignore it, so JXTreeTable inherits this broken behaviour.
if (UIManager.get("Table.alternateRowColor") != null) {
addHighlighter(oddRowHighlighter);
}
}
}
private static class DummyTreeTableNode extends DefaultMutableTreeTableNode {
private final Object[] values;
private DummyTreeTableNode(String name) {
super(name);
values = new Object[5];
values[0] = name;
}
private DummyTreeTableNode(Object... values) {
super(values[0]);
this.values = values;
}
@Override
public Object getValueAt(int column) {
return values[column];
}
}
private static class DummyTreeTableModel extends DefaultTreeTableModel {
private static DefaultMutableTreeTableNode rootNode = new DefaultMutableTreeTableNode();
static {
DefaultMutableTreeTableNode blue = new DefaultMutableTreeTableNode("Blue");
blue.add(new DummyTreeTableNode("Orionis C", 33000, 30000.0, 18.0, 5.90));
rootNode.add(blue);
DefaultMutableTreeTableNode bluish = new DefaultMutableTreeTableNode("Bluish");
bluish.add(new DummyTreeTableNode("Becrux", 30000, 16000.0, 16.0, 5.70));
bluish.add(new DummyTreeTableNode("Spica", 22000, 8300.0, 10.5, 5.10));
bluish.add(new DummyTreeTableNode("Achernar", 15000, 750.0, 5.40, 3.70));
bluish.add(new DummyTreeTableNode("Rigel", 12500, 130.0, 3.50, 2.70));
rootNode.add(bluish);
DefaultMutableTreeTableNode blueWhite = new DefaultMutableTreeTableNode("Blue-White");
blueWhite.add(new DummyTreeTableNode("Sirius A", 9500, 63.0, 2.60, 2.30));
blueWhite.add(new DummyTreeTableNode("Fomalhaut", 9000, 40.0, 2.20, 2.00));
blueWhite.add(new DummyTreeTableNode("Altair", 8700, 24.0, 1.90, 1.80));
rootNode.add(blueWhite);
DefaultMutableTreeTableNode white = new DefaultMutableTreeTableNode("White");
white.add(new DummyTreeTableNode("Polaris A", 7400, 9.0, 1.60, 1.50));
white.add(new DummyTreeTableNode("Eta Scorpii", 7100, 6.3, 1.50, 1.30));
white.add(new DummyTreeTableNode("Procyon A", 6400, 4.0, 1.35, 1.20));
rootNode.add(white);
DefaultMutableTreeTableNode yellowWhite = new DefaultMutableTreeTableNode("Yellow-White");
yellowWhite.add(new DummyTreeTableNode("Alpha Centauri A", 5900, 1.45, 1.08, 1.05));
yellowWhite.add(new DummyTreeTableNode("The Sun", 5800, 100.0, 1.00, 1.00));
yellowWhite.add(new DummyTreeTableNode("Mu Cassiopeiae", 5600, 0.70, 0.95, 0.91));
yellowWhite.add(new DummyTreeTableNode("Tau Ceti", 5300, 0.44, 0.85, 0.87));
rootNode.add(yellowWhite);
DefaultMutableTreeTableNode orange = new DefaultMutableTreeTableNode("Orange");
orange.add(new DummyTreeTableNode("Pollux", 5100, 0.36, 0.83, 0.83));
orange.add(new DummyTreeTableNode("Epsilon Eridani", 4830, 0.28, 0.78, 0.79));
orange.add(new DummyTreeTableNode("Alpha Centauri B", 4370, 0.18, 0.68, 0.74));
rootNode.add(orange);
DefaultMutableTreeTableNode red = new DefaultMutableTreeTableNode("Red");
red.add(new DummyTreeTableNode("Lalande 21185", 3400, 0.03, 0.33, 0.36));
red.add(new DummyTreeTableNode("Ross 128", 3200, 0.0005, 0.20, 0.21));
red.add(new DummyTreeTableNode("Wolf 359", 3000, 0.0002, 0.10, 0.12));
rootNode.add(red);
}
private static final Object[] columnNames = {
"Star", "Temperature (K)", "Luminosity", "Mass", "Radius"
};
public DummyTreeTableModel() {
super(rootNode, Arrays.asList(columnNames));
}
@Override
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex == 0) {
return String.class;
} else {
return Double.class;
}
}
@Override
public boolean isCellEditable(Object node, int column) {
return false;
}
}
}
第一轮进一步调查:
我最终通过观察 JXTreeTable
中的绘制方法成功地捕获了调试器中的条件。我看到的是它有一个名为 ClippedTreeCellRenderer
的东西,其中有一些字段看起来与可疑行为相对应:
iconRect = {java.awt.Rectangle@2946}"java.awt.Rectangle[x=20,y=92,width=16,height=16]"
textRect = {java.awt.Rectangle@2947}"java.awt.Rectangle[x=20,y=-17,width=62,height=15]"
itemRect = {java.awt.Rectangle@2948}"java.awt.Rectangle[x=20,y=36,width=103,height=18]"
我还没有确认它确实使用这个值来绘制矩形,但是 textRect
正是它重新绘制的小窗口的大小。所以现在的问题是,JXTreeTable
到底从哪里提取这些值以及为什么要使用它们?
我的直觉告诉我,JXTreeTable
的渲染器以某种方式使用树单元渲染器直接渲染单元,而不是仅仅告诉树本身进行绘制。绘制行背景和展开/折叠图标的逻辑位于树中,而不是单元格中,因此如果它这样做,那么它没有一致地绘制树是有道理的。
第二轮进一步调查:
我认为我完全走错了路。看起来整行正在被绘制,但是tree.isPathSelected(path)为新选择的蓝色行返回false
并返回true
对于刚刚取消选择的行。
我可以通过 DefaultTreeSelectionModel
中的断点确认树选择仅在您放开鼠标后才会更新,这就是它最终恢复正确渲染的原因。
我必须进一步深入研究 JXTreeTable 以了解它如何保持这些同步。
最佳答案
我发现了这个错误。它看起来像是 JXTreeTable.java
中的一些善意代码,试图减少更新:
/**
* Class responsible for calling updateSelectedPathsFromSelectedRows
* when the selection of the list changse.
*/
class ListSelectionHandler implements ListSelectionListener {
@Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
updateSelectedPathsFromSelectedRows();
}
}
}
如果删除 if
检查,一切都会正常工作。我想我只需要对 SwingX 进行一些本地更改,因为该项目基本上已经死了。 :(
关于java - JXTreeTable、行条纹和适当的重画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23832023/
我想以 headless 模式(屏幕上根本没有 GUI)将 JPanel 绘制到 BufferedImage 中。 final JPanel panel = createPanel(); panel.
我是 Canvas 的新手,正在尝试创建看起来逼真的 float 粒子动画。 目前,我正在创建 400 个随机散布在 400x400 Canvas 上的粒子。 然后,在每个 requestAnimat
有没有办法在悬停时停止悬 float 画? :hover 这是一个显示动画的链接: https://codepen.io/youbiteme/pen/RprPrN 最佳答案 只需为您的 svg 悬停添
我想在谷歌地图上绘制覆盖图,其中除了特定点周围 1.5 公里半径以外的所有内容都被遮蔽了。为此,我尝试使用带有大量边框的圆圈,所以我会在边框中放置透明中心和覆盖颜色来实现这一点,但它无法渲染。
我正在尝试通过扩展类 UIView 来创建自定义 View ,该类可以在自定义 View 的中心显示一个圆圈。为了添加自定义绘图,我重写了 draw(_ rect: CGRect) 方法,如下所示。
我是一名优秀的程序员,十分优秀!