This commit is contained in:
Etienne VIENOT 2019-03-22 15:46:43 +01:00
commit 0ece74282d
10 changed files with 625 additions and 0 deletions

6
.classpath Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/bin/

17
.project Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ExempleJPanelConversation</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8

View File

@ -0,0 +1,8 @@
import packageIHM.MaJFrame;
public class ClassePrincipale {
public static void main(String[] args) {
MaJFrame maFen = new MaJFrame();
maFen.setVisible(true);
}
}

View File

@ -0,0 +1,158 @@
package packageIHM;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.regex.Pattern;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
public class JPanelConversation extends JPanel
{
private static final long serialVersionUID = 1L;
private ArrayList<Message> messages;
private TextBubble border;
private final int marginLeft = 0;
private final int marginTop = 0;
private final int thickness = 2;
private final int radius = 8;
private final int pointerSize = 10;
private int offset = 0;
private boolean initialized = false;
private int maxCharByLine = 50;
JPanelConversation(MaJFrame mjf, ArrayList<Message> messages) {
setLayout(null);
int posX = marginLeft;
int posY;
this.messages = messages;
JTextArea bubble = null;
for (Message msg : messages) {
if (bubble!=null) {
posY = bubble.getLocation().y+bubble.getHeight();
} else {
posY = marginTop;
}
bubble = new JTextArea(wrap(msg.getMessage(),maxCharByLine));
bubble.setDisabledTextColor(Color.BLACK);
bubble.setEnabled(false);
border = new TextBubble(msg.getColor(),thickness,radius,pointerSize, msg.getSide());
bubble.setBorder(border);
bubble.setOpaque(true);
bubble .setBackground(Color.WHITE);
bubble.setSize(bubble.getPreferredSize());
bubble.setLocation(posX, posY);
bubble.setLineWrap(true);
bubble.addMouseMotionListener(new RedispatchingMouseAdapter() );
add(bubble);
msg.setBubble(bubble);
msg.setPosY(posY);
}
}
private void createBubbleIfNecessary() {
int currentHeight = 0;
for (Message msg : messages) {
if (msg.getBubble()==null) {
JTextArea bubble = new JTextArea(wrap(msg.getMessage(),maxCharByLine));
bubble.setDisabledTextColor(Color.BLACK);
bubble.setEnabled(false);
border = new TextBubble(msg.getColor(),thickness,radius,pointerSize, msg.getSide());
bubble.setBorder(border);
bubble.setOpaque(true);
bubble.setBackground(Color.WHITE);
bubble.setSize(bubble.getPreferredSize());
bubble.setLocation(marginLeft, currentHeight);
bubble.setLineWrap(true);
add(bubble);
msg.setBubble(bubble);
msg.setPosY(currentHeight);
calculateOffsetToShowLastMessage();
} else {
currentHeight = currentHeight + msg.getBubble().getHeight();
}
}
}
private int getFullHeightMessage() {
int fullHeight = 0;
for (Message msg : messages) {
fullHeight = fullHeight + msg.getBubble().getHeight();
}
return fullHeight;
}
public void calculateOffsetToShowLastMessage() {
int fullHeight = getFullHeightMessage();
if (fullHeight>getHeight()) {
offset = fullHeight-getHeight();
}
}
public void up(int x) {
offset = offset + x;
}
public void down(int x) {
offset = offset - x;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (!initialized) {
calculateOffsetToShowLastMessage();
initialized=true;
}
createBubbleIfNecessary();
for (Message msg : messages) {
if (msg.getSide()==SwingConstants.RIGHT) {
msg.getBubble().setLocation(getWidth()-msg.getBubble().getWidth(), msg.getPosY()-offset);
} else {
msg.getBubble().setLocation(msg.getBubble().getX(), msg.getPosY()-offset);
}
}
}
private static final String linebreak = "\n"; // or "\r\n";
public static String wrap(String string, int lineLength) {
StringBuilder b = new StringBuilder();
for (String line : string.split(Pattern.quote(linebreak))) {
b.append(wrapLine(line, lineLength));
}
return b.toString();
}
private static String wrapLine(String line, int lineLength) {
if (line.length() == 0) return linebreak;
if (line.length() <= lineLength) return line + linebreak;
String[] words = line.split(" ");
StringBuilder allLines = new StringBuilder();
StringBuilder trimmedLine = new StringBuilder();
for (String word : words) {
if (trimmedLine.length() + 1 + word.length() <= lineLength) {
trimmedLine.append(word).append(" ");
} else {
allLines.append(trimmedLine).append(linebreak);
trimmedLine = new StringBuilder();
trimmedLine.append(word).append(" ");
}
}
if (trimmedLine.length() > 0) {
allLines.append(trimmedLine);
}
allLines.append(linebreak);
return allLines.toString();
}
}

View File

@ -0,0 +1,140 @@
package packageIHM;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
public class MaJFrame extends JFrame implements MouseMotionListener{
private static final long serialVersionUID = 7252959164975426293L;
private JPanel contentPane;
private JPanelConversation conversationPanel;
private JPanel panel;
private JTextField textFieldMsg;
private ArrayList<Message> messages;
private int previousY;
/**
* Create the frame.
*/
public MaJFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
panel = new JPanel();
panel.setBorder(new LineBorder(new Color(0, 0, 0)));
contentPane.add(panel, BorderLayout.NORTH);
panel.setLayout(new BorderLayout(0, 0));
Action action = new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
addMessage();
}
};
JButton buttonAdd = new JButton("Add");
panel.add(buttonAdd, BorderLayout.EAST);
buttonAdd.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addMessage();
}
});
textFieldMsg = new JTextField();
panel.add(textFieldMsg, BorderLayout.CENTER);
textFieldMsg.setColumns(10);
textFieldMsg.addActionListener(action);
messages = new ArrayList<Message>();
String msgLeft = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n"
+ "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.";
String msgRight = "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n"
+ "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum";
for (int i=0;i<20;i++) {
if (i%2==0) {
messages.add(new Message(Color.BLUE, i + " " + msgLeft, SwingConstants.LEFT));
} else {
messages.add(new Message(Color.RED, i + " " + msgRight, SwingConstants.RIGHT));
}
}
conversationPanel = new JPanelConversation(this, messages);
conversationPanel .setBackground(Color.WHITE);
conversationPanel.addMouseMotionListener(this);
contentPane.add(conversationPanel, BorderLayout.CENTER);
setContentPane(contentPane);
addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent componentEvent) {
conversationPanel.calculateOffsetToShowLastMessage();
}
});
}
public void addMessage() {
//panel.setImage("image1.jpg");
//panel_1.setImage("image2.png");
if (textFieldMsg.getText().length()>0) {
messages.add(new Message(Color.RED,textFieldMsg.getText(),SwingConstants.RIGHT));
conversationPanel.repaint();
textFieldMsg.setText("");
}
}
private void up(int x) {
conversationPanel.up(x);
conversationPanel.repaint();
}
private void down(int x) {
conversationPanel.down(x);
conversationPanel.repaint();
}
@Override
public void mouseDragged(MouseEvent e) {
int y = e.getY();
if (y < previousY) {
if (Math.abs(previousY-y)<60)
up(Math.abs(previousY-y));
} else if (y > previousY) {
if (Math.abs(previousY-y)<60)
down(Math.abs(previousY-y));
}
previousY = y;
}
@Override
public void mouseMoved(MouseEvent e) {
}
}

View File

@ -0,0 +1,68 @@
package packageIHM;
import java.awt.Color;
import javax.swing.JTextArea;
public class Message {
private Color color;
private String message;
private int side;
private JTextArea bubble;
private int posY;
public Message(Color color, String message, int side) {
super();
this.color = color;
this.message = message;
this.side = side;
this.posY = -1;
bubble = null;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getSide() {
return side;
}
public void setSide(int side) {
this.side = side;
}
public JTextArea getBubble() {
return bubble;
}
public void setBubble(JTextArea graphics) {
this.bubble = graphics;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
}

View File

@ -0,0 +1,51 @@
package packageIHM;
import java.awt.Component;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.SwingUtilities;
public class RedispatchingMouseAdapter implements MouseListener, MouseWheelListener, MouseMotionListener{
public void mouseClicked(MouseEvent e) {
redispatchToParent(e);
}
public void mousePressed(MouseEvent e) {
redispatchToParent(e);
}
public void mouseReleased(MouseEvent e) {
redispatchToParent(e);
}
public void mouseEntered(MouseEvent e) {
redispatchToParent(e);
}
public void mouseExited(MouseEvent e) {
redispatchToParent(e);
}
public void mouseWheelMoved(MouseWheelEvent e){
redispatchToParent(e);
}
public void mouseDragged(MouseEvent e){
redispatchToParent(e);
}
public void mouseMoved(MouseEvent e) {
redispatchToParent(e);
}
private void redispatchToParent(MouseEvent e){
Component source = (Component) e.getSource();
MouseEvent parentEvent = SwingUtilities.convertMouseEvent(source, e, source.getParent());
source.getParent().dispatchEvent(parentEvent);
}
}

View File

@ -0,0 +1,165 @@
package packageIHM;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.Area;
import java.awt.geom.RoundRectangle2D;
import javax.swing.SwingConstants;
import javax.swing.border.AbstractBorder;
class TextBubble extends AbstractBorder {
private static final long serialVersionUID = 1L;
private Color color;
private int thickness;
private int radius;
private int pointerSize = 0;
private Insets insets = null;
private BasicStroke stroke = null;
private int strokePad;
private double pointerPadPercent = 0.5;
int pointerSide = SwingConstants.TOP;
private RenderingHints hints;
TextBubble(Color color, int thickness, int radius, int pointerSize, int pointerSide) {
this.color = color;
this.thickness = thickness;
this.radius = radius;
this.pointerSize = pointerSize;
hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
insets = new Insets(0, 0, 0, 0);
this.pointerSide = pointerSide;
setThickness(thickness);
}
public TextBubble setThickness(int n) {
thickness = n < 0? 0: n;
stroke = new BasicStroke(thickness);
strokePad = thickness / 2;
setPointerSize(pointerSize);
return this;
}
public TextBubble setPointerSize(int size) {
int pad = radius/2 + strokePad;
int pointerSidePad = pad + pointerSize + strokePad;
int left, right, bottom, top;
left = right = bottom = top = pad;
switch (pointerSide) {
case SwingConstants.TOP:
top = pointerSidePad;
break;
case SwingConstants.LEFT:
left = pointerSidePad;
break;
case SwingConstants.RIGHT:
right = pointerSidePad;
break;
default:
case SwingConstants.BOTTOM:
bottom = pointerSidePad;
break;
}
insets.set(top, left, bottom, right);
return this;
}
@Override
public Insets getBorderInsets(Component c) {
return insets;
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Color bg = new Color(color.getRed(), color.getGreen(), color.getBlue(), 125);
g.setColor(bg);
g.fillRect(0, 0, width, height);
Graphics2D g2 = (Graphics2D) g;
g2.setBackground(c.getBackground());
RoundRectangle2D.Double bubble;
Polygon pointer = new Polygon();
{
int rx, ry, rw, rh;
rx = ry = strokePad;
rw = width - thickness;
rh = height - thickness;
switch (pointerSide) {
case SwingConstants.LEFT:
rx += pointerSize;
case SwingConstants.RIGHT:
rw -= pointerSize;
break;
case SwingConstants.TOP:
ry += pointerSize;
case SwingConstants.BOTTOM:
default:
rh -= pointerSize;
break;
}
bubble = new RoundRectangle2D.Double(rx,ry,rw,rh,radius, radius);
int pointerPad;
if (pointerSide == SwingConstants.LEFT || pointerSide == SwingConstants.RIGHT) {
pointerPad = (int) (pointerPadPercent * (height-radius*2-pointerSize));
} else {
pointerPad = (int) (pointerPadPercent * (width-radius*2-pointerSize));
}
int basePad = strokePad + radius + pointerPad;
switch (pointerSide) {
case SwingConstants.LEFT:
pointer.addPoint(rx, basePad);// top
pointer.addPoint(rx, basePad+pointerSize);// bottom
pointer.addPoint(strokePad, basePad+pointerSize/2);
break;
case SwingConstants.RIGHT:
pointer.addPoint(rw, basePad);// top
pointer.addPoint(rw, basePad+pointerSize);// bottom
pointer.addPoint(width-strokePad, basePad+pointerSize/2);
break;
case SwingConstants.TOP:
pointer.addPoint(basePad, ry);// left
pointer.addPoint(basePad + pointerSize, ry);// right
pointer.addPoint(basePad + (pointerSize / 2), strokePad);
break;
default:
case SwingConstants.BOTTOM:
pointer.addPoint(basePad, rh);// left
pointer.addPoint(basePad + pointerSize, rh);// right
pointer.addPoint(basePad + (pointerSize / 2), height - strokePad);
break;
}
}
Area area = new Area(bubble);
area.add(new Area(pointer));
g2.setRenderingHints(hints);
Area spareSpace = new Area(new Rectangle(0, 0, width, height));
spareSpace.subtract(area);
g2.setClip(spareSpace);
g2.clearRect(0, 0, width, height);
g2.setClip(null);
g2.setColor(color);
g2.setStroke(stroke);
g2.draw(area);
}
}