Я пытался лучше понять области просмотра, поэтому я создал вертикальную временную шкалу, которую можно поместить в представление заголовка строки JScrollPane. Это работает, но когда я продолжил исследование, оно появляется при прокрутке вниз по aws областям компонента, которые не видны. Я только ожидал, что он нарисует видимую область на основе Graphics.getClipBounds (), но по мере того, как я продолжаю прокручивать его вниз, все больше и больше компонента * * * увеличивается до тех пор, пока внизу распечатки не покажут, что я рисую всю высоту. компонент.
Кажется, что-то не так с моим вычислением topMillis, но endMillis (который основан на topMillis) выглядит правильно.
Чтобы увидеть проблему, запустите программу и обратите внимание на Разница между topMillis и endMillis увеличивается при прокрутке вниз. Я ожидал, что разница останется прежней, так как это должна быть область, видимая пользователю.
На заметку о том, есть ли еще более эффективный способ нарисовать этот компонент? Простой способ - рисовать весь компонент каждый раз. Это становится непомерно большим, если временной диапазон становится слишком большим. То, как я это делаю, должно быть более эффективным, поскольку мы рисуем только то, что видно пользователю, независимо от того, насколько велик временной диапазон. Но мой подход напрямую связан с размером панели данных, что кажется проблематичным c. Можно ли сделать так, чтобы мой компонент соответствовал размеру области просмотра заголовка строки, но при этом точно отображал то, что пользователь прокручивает на панели прокрутки?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
public class TimeBarTest {
private static final int DATA_HEIGHT = 1000;
private final JScrollPane mScrollPane;
private TimeBar mRowHeaderView;
TimeBarTest() {
JPanel dataPanel = new JPanel();
dataPanel.setPreferredSize(new Dimension(0, DATA_HEIGHT));
mScrollPane = new JScrollPane(dataPanel);
mScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
mScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JButton cornerButton = new JButton("Hi");
cornerButton.addActionListener(pEvent -> {
mRowHeaderView.setTime(System.currentTimeMillis());
mScrollPane.getVerticalScrollBar().setValue(0);
});
cornerButton.setPreferredSize(new Dimension(20, 20));
JPanel columnHeader = new JPanel(new BorderLayout());
columnHeader.setPreferredSize(new Dimension(0, 30));
columnHeader.setBorder(BorderFactory.createLineBorder(Color.GRAY));
columnHeader.add(new JLabel("Column Header", SwingConstants.CENTER), BorderLayout.CENTER);
mRowHeaderView = new TimeBar(DATA_HEIGHT);
mScrollPane.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER, cornerButton);
mScrollPane.setRowHeaderView(mRowHeaderView);
mScrollPane.setColumnHeaderView(columnHeader);
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.setPreferredSize(new Dimension(500, 475));
contentPane.add(mScrollPane, BorderLayout.CENTER);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String... args) {
SwingUtilities.invokeLater(() -> new TimeBarTest());
}
private class TimeBar extends JComponent {
private final int MAJOR_TICK_LENGTH = 8;
private final int MINOR_TICK_LENGTH = 4;
private final int MINUTES_PER_MAJOR = 5;
private final int MINUTES_PER_MINOR = 1;
private final long MILLIS_PER_PIXEL = 4000;
private final long MILLIS_PER_MAJOR = TimeUnit.MINUTES.toMillis(MINUTES_PER_MAJOR);
private final long MILLIS_PER_MINOR = TimeUnit.MINUTES.toMillis(MINUTES_PER_MINOR);
private final SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat("hh:mm");
private long mTime;
TimeBar(int pHeight) {
setPreferredSize(new Dimension(50, pHeight));
mTime = System.currentTimeMillis();
}
public void setTime(long pTime) {
mTime = pTime;
repaint();
}
@Override
protected void paintComponent(Graphics pGraphics) {
super.paintComponent(pGraphics);
pGraphics.setColor(Color.black);
Rectangle clipBounds = pGraphics.getClipBounds();
Rectangle visibleRect = getVisibleRect();
// Determine the start and end time based on the visible area.
long topMillis = mTime - (clipBounds.y * MILLIS_PER_PIXEL);
long endMillis = topMillis - ((clipBounds.y + clipBounds.height) * MILLIS_PER_PIXEL);
// Determine where we should start drawing the ticks.
long startMillis = topMillis - (topMillis % MILLIS_PER_MINOR);
System.out.println(" clipBounds=" + clipBounds);
System.out.println(" visibleRect=" + visibleRect);
SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm:ss");
System.out.println(" origTime=" + dateFormat.format(new Date(mTime)));
System.out.println(" topTime=" + dateFormat.format(new Date(topMillis)));
System.out.println(" startMillis=" + dateFormat.format(new Date(startMillis)));
System.out.println(" endTime=" + dateFormat.format(new Date(endMillis)));
System.out.println(" topMillis=" + topMillis);
System.out.println(" startMillis=" + startMillis);
System.out.println(" endMillis=" + endMillis);
System.out.println("millisPerMajor=" + MILLIS_PER_MAJOR);
System.out.println("millisPerMinor=" + MILLIS_PER_MINOR);
// Draw the ticks and labels backwards through time.
for (long i = startMillis; i >= endMillis; i -= MILLIS_PER_MINOR) {
int pixel = (int) ((topMillis - i) / MILLIS_PER_PIXEL);
System.out.println("pixel=" + pixel);
if (i % MILLIS_PER_MAJOR == 0) {
String text = mSimpleDateFormat.format(new Date(i));
pGraphics.drawString(text, 1, (int) (pixel + 4));
pGraphics.drawLine(clipBounds.width, (int) pixel, clipBounds.width - MAJOR_TICK_LENGTH, (int) pixel);
} else {
pGraphics.drawLine(clipBounds.width, (int) pixel, clipBounds.width - MINOR_TICK_LENGTH, (int) pixel);
}
}
}
}
}