public class Comment { private final String text; private final Font font; private final Color fontColor; private double x; private int y; private final int width; private final int height; private final int margin = 10; private final long createdDate = System.nanoTime(); // Constructor, getter/setter, equals, hashCode は省略}
Text
public class CommentFrame extends JFrame { public CommentFrame() { // 画面中央に寄せる setLocationRelativeTo(null); // 画面のデコレーション(閉じるボタンとか)を切らないと透明にならない setUndecorated(true); setBackground(new Color(0,0,0,0)); getContentPane().setBackground(new Color(0,0,0,0)); setSize(800, 600); setResizable(true); setVisible(true); //表示! }}
Text
public class CommentPanel extends JPanel { // 今あるコメントを保存する private List<Comment> commentList = new LinkedList<>(); public CommentPanel(Color backgroundColor, Color borderColor) { // 枠の色を設定 setBorder(new LineBorder(borderColor)); setBackground(backgroundColor); // コメントの位置は絶対座標で指定したいのでレイアウトは指定しない setLayout(null); }}
@Overridepublic void paintComponent(Graphics g) { super.paintComponent(g); // リストにあるコメントを全部描画する for(Comment c : commentList) { g.setFont(c.getFont()); // あとで使います // g.setColor(Color.GRAY); // paintFontBorder(g, c, 2); g.setColor(c.getFontColor()); int x = c.getX(); int y = c.getY() + c.getHeight() - c.getMargin(); g.drawString(c.getText(), x, y); }}public void paintComments(List<Comment> commentList) { this.commentList = commentList; repaint(); //paintComponentを呼び出すおまじない}
Text
private void paintFontBorder(Graphics g, Comment c, int borderSize) { for(int i = -borderSize; i <= borderSize; i++) { for(int j = -borderSize; j <= borderSize; j++) { int x = c.getX() + i; int y = c.getY() + j + c.getHeight() - c.getMargin(); g.drawString(c.getText(), x, y); } }}
Text
public class CommentProvider { // フレーム本体をメモしておく private final CommentFrame SCREEN; private final List<Comment> ACTIVE_COMMENTS = Collections.synchronizedList(new LinkedList<>()); private final Queue<String> COMMENT_STR_QUEUE = new ConcurrentLinkedQueue<>(); private final Set<Comment> NEW_COMMENTS = Collections.synchronizedSet(new HashSet<>()); private final TreeSet<Integer> INSERTABLE_Y = new TreeSet<>(); private final Timer TIMER = new Timer(10, e -> moveComments()); private final int FONT_HEIGHT; public CommentProvider(CommentFrame SCREEN) { this.SCREEN = SCREEN; this.FONT_HEIGHT = config.FONT_SIZE + 20; //20はマージン分 refreshInsertableY(); } // 画面をフォントの高さで割って挿入可能な高さリストをつくる public void refreshInsertableY() { synchronized(INSERTABLE_Y) { for(int i = 0; i + FONT_HEIGHT <= SCREEN.getHeight(); i += FONT_HEIGHT) { INSERTABLE_Y.add(i); } } }}
Text
public void addComment(String comment) { System.err.println(comment); if(!canInsert()) return; COMMENT_STR_QUEUE.add(comment);}public synchronized boolean canInsert() { return !INSERTABLE_Y.isEmpty();}private synchronized int pollOptimalY() { Integer ret = INSERTABLE_Y.pollFirst(); return ret == null ? - FONT_HEIGHT : ret;}