如何在我要绘制的形状内插入文本 Java
How to insert text inside a shape that i will draw in Java
所以我想在形状中插入文本。该形状将由用户绘制,例如矩形。释放鼠标时,会发送一条弹出消息 "Enter name:"。用户输入矩形的名称,然后它直接出现在形状矩形内。
你能指导我实现这个目标吗?这样做的正确方法是什么?
我已经有了我的代码块,我可以在其中绘制矩形并发送弹出消息,但我不知道如何放置 "text inside the shape"
这是绘制形状的用户界面。
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Scanner;
import javax.imageio.ImageIO;
import javax.swing.Box;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class Lesson49_1 extends JFrame {
private int c;
public int getC() {
return c;
}
public void setC(int c) {
this.c= this.c;
}
private static final long serialVersionUID = -140274271716086522L;
JMenuBar menubar;
JMenu File, Exit;
JMenuItem New, Open;
JComponent DrawingBoard;
Font textFont;
String text;
Color textColor;
{
textColor = new Color(0x404000);
text = "Hello, World!";
}
JButton lineBut, ellipseBut, rectBut, strokeBut;
DecimalFormat dec = new DecimalFormat("#.##");
// Contains all of the rules for drawing
Graphics2D graphSettings;
// Going to be used to monitor what shape to draw next
int currentAction = 1;
// Transparency of the shape
// Default stroke and fill colors
Color strokeColor = Color.BLACK;
public static void main(String[] args) {
new Lesson49_1();
}
public Lesson49_1() {
// Define the defaults for the JFrame
this.setSize(800, 600);
this.setTitle("ERD BUILDER");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setJMenuBar(menubar);
JMenuBar menuBar = new JMenuBar();
// Add the menubar to the frame
setJMenuBar(menuBar);
// Define and add two drop down menu to the menubar
JMenu fileMenu = new JMenu("File");
JMenu editMenu = new JMenu("Edit");
JMenu dbMenu = new JMenu("Database");
JMenu ToolsMenu = new JMenu("Tools");
JMenu HelpMenu = new JMenu("Help");
menuBar.add(fileMenu);
menuBar.add(editMenu);
menuBar.add(dbMenu);
menuBar.add(ToolsMenu);
menuBar.add(HelpMenu);
// Create and add simple menu item to one of the drop down menu
JMenuItem newAction = new JMenuItem("New Project");
JMenuItem openAction = new JMenuItem("Open File");
JMenuItem exitAction = new JMenuItem("Quit");
JMenuItem cutAction = new JMenuItem("Cut");
JMenuItem copyAction = new JMenuItem("Copy");
JMenuItem pasteAction = new JMenuItem("Paste");
JMenuItem UndoAction = new JMenuItem("Undo");
JMenuItem RedoAction = new JMenuItem("Redo");
JMenuItem clearAction = new JMenuItem("Clear");
JMenuItem saveAction = new JMenuItem("Save");
JMenuItem exportAction = new JMenuItem("Export");
JMenuItem printAction = new JMenuItem("Print");
JMenuItem ConvertAction = new JMenuItem("Convert To Tables");
JMenuItem ColorAction = new JMenuItem("Color Picker");
JMenuItem ZoomAction = new JMenuItem("Zoom");
JMenuItem EntityAction = new JMenuItem("Entity & Attributes");
JMenuItem RelationshipAction = new JMenuItem("Relationship Attributes");
JMenuItem HelpAction = new JMenuItem("Help");
JMenuItem AboutAction = new JMenuItem("About");
fileMenu.add(newAction);
fileMenu.addSeparator();
fileMenu.add(openAction);
fileMenu.addSeparator();
fileMenu.add(saveAction);
fileMenu.addSeparator();
fileMenu.add(exportAction);
fileMenu.addSeparator();
fileMenu.add(printAction);
fileMenu.addSeparator();
fileMenu.add(exitAction);
editMenu.add(UndoAction);
editMenu.addSeparator();
editMenu.add(RedoAction);
editMenu.addSeparator();
editMenu.add(cutAction);
editMenu.addSeparator();
editMenu.add(copyAction);
editMenu.addSeparator();
editMenu.add(pasteAction);
editMenu.addSeparator();
editMenu.add(clearAction);
dbMenu.add(ConvertAction);
ToolsMenu.add(ColorAction);
ToolsMenu.addSeparator();
ToolsMenu.add(ZoomAction);
ToolsMenu.addSeparator();
ToolsMenu.add(EntityAction);
ToolsMenu.addSeparator();
ToolsMenu.add(RelationshipAction);
HelpMenu.add(HelpAction);
HelpMenu.addSeparator();
HelpMenu.add(AboutAction);
exitAction.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}}
);
ConvertAction.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//new ConvertForm().setVisible(true);
}}
);
newAction.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
new Lesson49_1().setVisible(true);
}
});
JPanel buttonPanel = new JPanel();
JPanel FieldPanel = new JPanel();
// Swing box that will hold all the buttons
Box theBox = Box.createVerticalBox();
Box theBoxs = Box.createVerticalBox();
// Make all the buttons in makeMeButtons by passing the
// button icon.
lineBut = makeMeButtons("./src/line.png", 2);
ellipseBut = makeMeButtons("./src/ellipse.png", 3);
rectBut = makeMeButtons("./src/rectangle.png", 4);
// Make all the buttons in makeMeColorButton by passing the
// button icon and true for stroke color or false for fill
strokeBut = makeMeColorButton("./src/stroke.png", 5, true);
// Add the fields to the boxs
//theBox.add(brushBut);
theBox.add(lineBut);
theBox.add(ellipseBut);
theBox.add(rectBut);
theBox.add(strokeBut);
buttonPanel.add(theBox);
FieldPanel.add(theBoxs);
this.add(buttonPanel, BorderLayout.WEST);
this.add(FieldPanel, BorderLayout.EAST);
buttonPanel.setPreferredSize(new Dimension(200,480));
FieldPanel.setPreferredSize(new Dimension(200,480));
// Make the drawing area take up the rest of the frame
// this.add(new DrawingBoard(), BorderLayout.CENTER);
final DrawingBoard drawPanel = new DrawingBoard();
this.add(drawPanel, BorderLayout.CENTER);
this.getContentPane().setBackground(Color.WHITE);
exportAction.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
BufferedImage image = new BufferedImage(drawPanel.getWidth(),
drawPanel.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
drawPanel.paint(g);
g.dispose();
JFileChooser fileChooser = new JFileChooser();
File theDirectory = new File("C:/Users/Wenda/Desktop");
fileChooser.setCurrentDirectory(theDirectory);
FileNameExtensionFilter pngFilter = new FileNameExtensionFilter(
"PNG file (*.png)", "png");
fileChooser.addChoosableFileFilter(pngFilter);
fileChooser.setFileFilter(pngFilter);
int status = fileChooser.showSaveDialog(Lesson49_1.this);
if (status == JFileChooser.APPROVE_OPTION) {
try {
ImageIO.write(image, "png",
fileChooser.getSelectedFile());
JOptionPane.showMessageDialog(null, "Image saved to "
+ fileChooser.getSelectedFile().getName());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
});
// Show the frame
this.setVisible(true);
}
public JButton makeMeButtons(String iconFile, final int actionNum) {
JButton theBut = new JButton();
Icon butIcon = new ImageIcon(iconFile);
theBut.setIcon(butIcon);
theBut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
currentAction = actionNum;
}
});
return theBut;
}
// Spits out buttons based on the image supplied and
// whether a stroke or fill is to be defined
public JButton makeMeColorButton(String iconFile, final int actionNum,
final boolean stroke) {
JButton theBut = new JButton();
Icon butIcon = new ImageIcon(iconFile);
theBut.setIcon(butIcon);
theBut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (stroke) {
// JColorChooser is a popup that lets you pick a color
strokeColor = JColorChooser.showDialog(null,
"Pick a Stroke", Color.BLACK);
} else {
}
}
});
return theBut;
}
public class DrawingBoard extends JComponent {
Font textFont = new Font("Arial", Font.BOLD, 12);
private static final long serialVersionUID = -4431176095451940075L;
// ArrayLists that contain each shape drawn along with
// that shapes stroke and fill
ArrayList<Shape> shapes = new ArrayList<Shape>();
ArrayList<Color> shapeStroke = new ArrayList<Color>();
ArrayList<Integer> count = new ArrayList<Integer>();
Point drawStart, drawEnd;
// Monitors events on the drawing area of the frame
public DrawingBoard() {
this.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
if (currentAction != 1) {
// When the mouse is pressed get x & y position
drawStart = new Point(e.getX(), e.getY());
drawEnd = drawStart;
repaint();
}
}
public void mouseReleased(MouseEvent e) {
int counts =0;
if (currentAction != 1) {
Shape aShape = null;
if (currentAction == 2) {
aShape = drawLine(drawStart.x, drawStart.y,
e.getX(), e.getY());
shapes.add(aShape);
shapeStroke.add(strokeColor);
drawStart = null;
drawEnd = null;
repaint();
} else
if (currentAction == 3) {
aShape = drawEllipse(drawStart.x, drawStart.y,
e.getX(), e.getY());
shapes.add(aShape);
shapeStroke.add(strokeColor);
drawStart = null;
drawEnd = null;
repaint();
counts = counts+1;
count.add(counts);
int sizes = count.size();
System.out.println(sizes);
// new AttributeForm().setVisible(true);
} else
if (currentAction == 4) {
//draw the rectangle
aShape = drawRectangle(drawStart.x, drawStart.y,
e.getX(), e.getY());
shapes.add(aShape);
shapeStroke.add(strokeColor);
drawStart = null;
drawEnd = null;
String text = (String) JOptionPane.showInputDialog(DrawingBoard, "Enter name:");
while (text == null || text.isEmpty()) {
text = (String) JOptionPane.showInputDialog(DrawingBoard, "You must enter a valid name! Please try again:");
}
repaint();
//new EntityForm().setVisible(true);
}
// Add shapes, fills and colors to there ArrayLists
}
}
});
this.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent me) {
JTextField name = new JTextField(15);
super.mouseClicked(me);
for (Shape s : shapes) {
if (s.contains(me.getPoint())) {//check if mouse is clicked within shape
//we can either just print out the object class name
System.out.println("Clicked a "+s.getClass().getName());
//or check the shape class we are dealing with using instance of with nested if
if (s instanceof Rectangle2D) {
//create table
}
else if (s instanceof Ellipse2D) {
}
}
}
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
// If this is a brush have shapes go on the screen quickly
if (currentAction == 1) {
int x = e.getX();
int y = e.getY();
Shape aShape = null;
shapes.add(aShape);
shapeStroke.add(strokeColor);
// Add the transparency value
}
// Get the final x & y position after the mouse is dragged
drawEnd = new Point(e.getX(), e.getY());
repaint();
}
});
}
public void paint(Graphics g) {
final int width = getWidth();
final int height = getHeight();
final double size = Math.sqrt(width * height);
// Class used to define the shapes to be drawn
graphSettings = (Graphics2D) g;
// Antialiasing cleans up the jagged lines and defines rendering
// rules
graphSettings.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Defines the line width of the stroke
graphSettings.setStroke(new BasicStroke(4));
// Iterators created to cycle through strokes and fills
Iterator<Color> strokeCounter = shapeStroke.iterator();
for (Shape s : shapes) {
// Grabs the next stroke from the color arraylist
graphSettings.setPaint(strokeCounter.next());
graphSettings.draw(s);
}
// Guide shape used for drawing
if (drawStart != null && drawEnd != null) {
// Makes the guide shape transparent
graphSettings.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, 0.40f));
// Make guide shape gray for professional look
graphSettings.setPaint(Color.LIGHT_GRAY);
Shape aShape = null;
if (currentAction == 2) {
aShape = drawLine(drawStart.x, drawStart.y, drawEnd.x,
drawEnd.y);
} else
if (currentAction == 3) {
aShape = drawEllipse(drawStart.x, drawStart.y, drawEnd.x,
drawEnd.y);
} else
if (currentAction == 4) {
// Create a new rectangle using x & y coordinates
aShape = drawRectangle(drawStart.x, drawStart.y, drawEnd.x,
drawEnd.y);
//Add text inside the rectangle
g.setColor(Color.black);
Font textFont = this.textFont.deriveFont((float) size * (1 / 12f));
g.setFont(textFont);
FontMetrics textMetrics = g.getFontMetrics();
g.drawString(text, (width - textMetrics.stringWidth(text)) / 2, (textMetrics.getAscent() + (height - (textMetrics.getAscent() + textMetrics.getDescent())) / 2));
FontMetrics fm = g.getFontMetrics();
int fontAscent = fm.getAscent();
int stringX = Math.min(drawStart.x, drawEnd.x);
int stringY = Math.min(drawStart.y, drawEnd.y) + fontAscent;
g.drawString(text, stringX, stringY);
}
graphSettings.draw(aShape);
}
}
private Rectangle2D.Float drawRectangle(int x1, int y1, int x2, int y2) {
// Get the top left hand corner for the shape
// Math.min returns the points closest to 0
int x = Math.min(x1, x2);
int y = Math.min(y1, y2);
// Gets the difference between the coordinates and
int width = Math.abs(x1 - x2);
int height = Math.abs(y1 - y2);
return new Rectangle2D.Float(x, y, width, height);
}
private Ellipse2D.Float drawEllipse(int x1, int y1, int x2, int y2) {
int x = Math.min(x1, x2);
int y = Math.min(y1, y2);
int width = Math.abs(x1 - x2);
int height = Math.abs(y1 - y2);
return new Ellipse2D.Float(x, y, width, height);
}
private Line2D.Float drawLine(int x1, int y1, int x2, int y2) {
return new Line2D.Float(x1, y1, x2, y2);
}
public void drawString(String text,int stringX, int stringY){
}
}
}
EntityForm 是获取矩形名称的窗体。这是一个简单的形式 "Enter name:"
"CODE EDITED(3)"
试试这个:
public class MyCanvas extends JPanel {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.getContentPane().add(new MyCanvas(), BorderLayout.CENTER);
frame.setSize(400, 400);
frame.setMinimumSize(frame.getSize());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
Color rectColor;
Color textColor;
Font textFont;
String text;
{
rectColor = new Color(0x0060FF);
textColor = new Color(0x404000);
textFont = new Font("Arial", Font.BOLD, 12);
text = "Hello, World!";
}
@Override
public void paint(Graphics g) {
final int width = getWidth();
final int height = getHeight();
final double size = Math.sqrt(width * height);
//setup
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//rectangle
g.clearRect(0, 0, width, height);
g.setColor(Color.blue);
int s = (int) (size * (1 / 10d));
g.fillRoundRect(0, 0, width, height, s, s);
//text
g.setColor(Color.black);
Font textFont = this.textFont.deriveFont((float) size * (1 / 12f));
g.setFont(textFont);
FontMetrics textMetrics = g.getFontMetrics();
g.drawString(text, (width - textMetrics.stringWidth(text)) / 2, (textMetrics.getAscent() + (height - (textMetrics.getAscent() + textMetrics.getDescent())) / 2));
}
}
所以你有两个问题:
- 如何获取用户输入的文本
- 如何在矩形中绘制文本
获取文本
您的 EntityForm class 应该有某种访问器方法来获取文本字段本身或文本字段的值(即用户输入的文本)。
我假设它还有一个 "Okay" 按钮供用户在输入文本后单击?因此,您需要先保存对新 EntityForm 的引用,然后将事件处理程序添加到 "okay" 按钮,然后再将其设置为可见。
因此,例如:
final EntityForm ef = new EntityForm();
ef.getOkayButton().addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
String text = ef.getTextInput().getText();
// draw text code here...
}
});
ef.setVisible(true);
以上显然只是一个示例,因为我不知道 EntityForm class 的 API,但它应该足以让您继续。如果您需要更具体的答案,那么您还需要 post EntityForm 的代码。
但是,比使用 EntityForm class 更简单的选择是使用内置的 JOptionPane.showInputDialog() 方法。因此,您可以这样做,而不是调用 new EntityForm()
:
String text = (String) JOptionPane.showInputDialog(drawingBoard, "Enter name:");
// Note that if the user presses "cancel" then text will be null. Also,
// user may not have entered any text and pressed "okay", so text will be
// an empty string.
if (text == null || text.isEmpty()) {
text = "[unnamed]";
}
// Instead of substituting for an alternative string, you could show
// an error message and ask the user for a name again until a valid
// name is supplied.e.g.:
/*
while (text == null || text.isEmpty()) {
text = (String) JOptionPane.showInputDialog(drawingBoard, "You must enter a valid name! Please try again:");
}
*/
// draw text code here...
绘制文本
此处需要Graphics2d#drawString() 方法之一。查看 API 文档以获取更多详细信息和选项,但其要点是:
// get the size of the current font
FontMetrics fm = g.getFontMetrics();
int fontAscent = fm.getAscent();
// drawString co-ordinates specify the baseline of the text, so lets
// tell it to draw at fontAscent pixels below the top of the rectangle.
// Note that the user might have started dragging from any corner of the
// rectangle, so we need to determine which co-ordinates represent the
// top-left most point of the rectangle by looking for the lowest value:
int stringX = Math.min(drawStart.x, drawEnd.x);
int stringY = Math.min(drawStart.y, drawEnd.y) + fontAscent;
// To add n pixles of padding between the rectangle edge and the string,
// just add n to the numbers passed in to the drawString() method here:
g.drawString(text, stringX stringY);
请注意,上面的代码并未尝试确保文本适合矩形。为此,您需要使用 fm.stringWidth(text)
,然后决定是否要裁剪绘制的文本、缩放它或减小字体大小直到它适合(它可能永远不会这样做)。所有这些都超出了这个问题的范围。
编辑
最近更改代码后,您现在在绘制方法中绘制字符串时遇到问题。问题是您没有在任何地方保存 JOptionPane.showInputDialog 返回的字符串。它被分配给一个名为 text
的局部范围变量,然后被丢弃。 (请注意,这不是 class 级变量 text
,因为您通过再次为其指定类型来声明一个新的局部变量;即,您正在使用 String text = ...
。但这不是实际问题。事实上,您可以摆脱 class-level text
变量并在拖动矩形时停止绘制它;不需要它。)
正如您已经在 class 级变量中存储了一个形状列表,以便在每次调用 paint()
时重新绘制,您还需要存储一个要绘制的字符串列表以及绘制它们的点。所以你需要一个新的 class 来将字符串与点相关联:
class DrawnString {
private final String text;
private final Point position;
// Insert constructor and getter methods here
}
然后您还需要 DrawingBoard
中的 class 级列表来存储这些实例,就像您的形状列表一样:
private List<DrawnString> strings = new ArrayList<DrawnString>();
现在,回到您的 mouseReleased
方法,在从 JOptionPane 获取文本之后,但在调用 repaint()
之前,您应该将字符串及其位置添加到 DrawnStrings 列表中。
// Note that you need to do this BEFORE you set drawStart and drawEnd to
// null, so move the lines where that is done to below these lines:
int stringX = Math.min(drawStart.x, drawEnd.x);
int stringY = Math.min(drawStart.y, drawEnd.y);
// now it's safe to discard these points:
drawStart = null;
drawEnd = null;
// Now save the string and its position in the list so that it can be
// redrawn every time paint() is called:
strings.add(new DrawnString(text, new Point(stringX, stringY)));
// Now we can call repaint():
repaint();
最后,在您的 paint()
方法中,绘制完所有形状后(即,在 for (Shape s : shapes)
循环之后),您应该绘制字符串:
// This is where you need to get the size of the font
FontMetrics fm = graphSettings.getFontMetrics();
int fontAscent = fm.getAscent();
for (DrawnString s : strings) {
Point p = s.getPosition();
// Draw with 2px padding, for example:
graphSettings.drawString(s.getText(), p.x + 2, p.y + fontAscent + 2);
}
最后,在 paint()
方法的末尾,在 if (currentAction == 4) {...}
块内,去掉那里的绘制字符串内容(即 //Add text inside the rectangle
评论之后的所有内容)。
瞧瞧!
所以我想在形状中插入文本。该形状将由用户绘制,例如矩形。释放鼠标时,会发送一条弹出消息 "Enter name:"。用户输入矩形的名称,然后它直接出现在形状矩形内。
你能指导我实现这个目标吗?这样做的正确方法是什么? 我已经有了我的代码块,我可以在其中绘制矩形并发送弹出消息,但我不知道如何放置 "text inside the shape"
这是绘制形状的用户界面。
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Scanner;
import javax.imageio.ImageIO;
import javax.swing.Box;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class Lesson49_1 extends JFrame {
private int c;
public int getC() {
return c;
}
public void setC(int c) {
this.c= this.c;
}
private static final long serialVersionUID = -140274271716086522L;
JMenuBar menubar;
JMenu File, Exit;
JMenuItem New, Open;
JComponent DrawingBoard;
Font textFont;
String text;
Color textColor;
{
textColor = new Color(0x404000);
text = "Hello, World!";
}
JButton lineBut, ellipseBut, rectBut, strokeBut;
DecimalFormat dec = new DecimalFormat("#.##");
// Contains all of the rules for drawing
Graphics2D graphSettings;
// Going to be used to monitor what shape to draw next
int currentAction = 1;
// Transparency of the shape
// Default stroke and fill colors
Color strokeColor = Color.BLACK;
public static void main(String[] args) {
new Lesson49_1();
}
public Lesson49_1() {
// Define the defaults for the JFrame
this.setSize(800, 600);
this.setTitle("ERD BUILDER");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setJMenuBar(menubar);
JMenuBar menuBar = new JMenuBar();
// Add the menubar to the frame
setJMenuBar(menuBar);
// Define and add two drop down menu to the menubar
JMenu fileMenu = new JMenu("File");
JMenu editMenu = new JMenu("Edit");
JMenu dbMenu = new JMenu("Database");
JMenu ToolsMenu = new JMenu("Tools");
JMenu HelpMenu = new JMenu("Help");
menuBar.add(fileMenu);
menuBar.add(editMenu);
menuBar.add(dbMenu);
menuBar.add(ToolsMenu);
menuBar.add(HelpMenu);
// Create and add simple menu item to one of the drop down menu
JMenuItem newAction = new JMenuItem("New Project");
JMenuItem openAction = new JMenuItem("Open File");
JMenuItem exitAction = new JMenuItem("Quit");
JMenuItem cutAction = new JMenuItem("Cut");
JMenuItem copyAction = new JMenuItem("Copy");
JMenuItem pasteAction = new JMenuItem("Paste");
JMenuItem UndoAction = new JMenuItem("Undo");
JMenuItem RedoAction = new JMenuItem("Redo");
JMenuItem clearAction = new JMenuItem("Clear");
JMenuItem saveAction = new JMenuItem("Save");
JMenuItem exportAction = new JMenuItem("Export");
JMenuItem printAction = new JMenuItem("Print");
JMenuItem ConvertAction = new JMenuItem("Convert To Tables");
JMenuItem ColorAction = new JMenuItem("Color Picker");
JMenuItem ZoomAction = new JMenuItem("Zoom");
JMenuItem EntityAction = new JMenuItem("Entity & Attributes");
JMenuItem RelationshipAction = new JMenuItem("Relationship Attributes");
JMenuItem HelpAction = new JMenuItem("Help");
JMenuItem AboutAction = new JMenuItem("About");
fileMenu.add(newAction);
fileMenu.addSeparator();
fileMenu.add(openAction);
fileMenu.addSeparator();
fileMenu.add(saveAction);
fileMenu.addSeparator();
fileMenu.add(exportAction);
fileMenu.addSeparator();
fileMenu.add(printAction);
fileMenu.addSeparator();
fileMenu.add(exitAction);
editMenu.add(UndoAction);
editMenu.addSeparator();
editMenu.add(RedoAction);
editMenu.addSeparator();
editMenu.add(cutAction);
editMenu.addSeparator();
editMenu.add(copyAction);
editMenu.addSeparator();
editMenu.add(pasteAction);
editMenu.addSeparator();
editMenu.add(clearAction);
dbMenu.add(ConvertAction);
ToolsMenu.add(ColorAction);
ToolsMenu.addSeparator();
ToolsMenu.add(ZoomAction);
ToolsMenu.addSeparator();
ToolsMenu.add(EntityAction);
ToolsMenu.addSeparator();
ToolsMenu.add(RelationshipAction);
HelpMenu.add(HelpAction);
HelpMenu.addSeparator();
HelpMenu.add(AboutAction);
exitAction.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}}
);
ConvertAction.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//new ConvertForm().setVisible(true);
}}
);
newAction.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
new Lesson49_1().setVisible(true);
}
});
JPanel buttonPanel = new JPanel();
JPanel FieldPanel = new JPanel();
// Swing box that will hold all the buttons
Box theBox = Box.createVerticalBox();
Box theBoxs = Box.createVerticalBox();
// Make all the buttons in makeMeButtons by passing the
// button icon.
lineBut = makeMeButtons("./src/line.png", 2);
ellipseBut = makeMeButtons("./src/ellipse.png", 3);
rectBut = makeMeButtons("./src/rectangle.png", 4);
// Make all the buttons in makeMeColorButton by passing the
// button icon and true for stroke color or false for fill
strokeBut = makeMeColorButton("./src/stroke.png", 5, true);
// Add the fields to the boxs
//theBox.add(brushBut);
theBox.add(lineBut);
theBox.add(ellipseBut);
theBox.add(rectBut);
theBox.add(strokeBut);
buttonPanel.add(theBox);
FieldPanel.add(theBoxs);
this.add(buttonPanel, BorderLayout.WEST);
this.add(FieldPanel, BorderLayout.EAST);
buttonPanel.setPreferredSize(new Dimension(200,480));
FieldPanel.setPreferredSize(new Dimension(200,480));
// Make the drawing area take up the rest of the frame
// this.add(new DrawingBoard(), BorderLayout.CENTER);
final DrawingBoard drawPanel = new DrawingBoard();
this.add(drawPanel, BorderLayout.CENTER);
this.getContentPane().setBackground(Color.WHITE);
exportAction.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
BufferedImage image = new BufferedImage(drawPanel.getWidth(),
drawPanel.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
drawPanel.paint(g);
g.dispose();
JFileChooser fileChooser = new JFileChooser();
File theDirectory = new File("C:/Users/Wenda/Desktop");
fileChooser.setCurrentDirectory(theDirectory);
FileNameExtensionFilter pngFilter = new FileNameExtensionFilter(
"PNG file (*.png)", "png");
fileChooser.addChoosableFileFilter(pngFilter);
fileChooser.setFileFilter(pngFilter);
int status = fileChooser.showSaveDialog(Lesson49_1.this);
if (status == JFileChooser.APPROVE_OPTION) {
try {
ImageIO.write(image, "png",
fileChooser.getSelectedFile());
JOptionPane.showMessageDialog(null, "Image saved to "
+ fileChooser.getSelectedFile().getName());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
});
// Show the frame
this.setVisible(true);
}
public JButton makeMeButtons(String iconFile, final int actionNum) {
JButton theBut = new JButton();
Icon butIcon = new ImageIcon(iconFile);
theBut.setIcon(butIcon);
theBut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
currentAction = actionNum;
}
});
return theBut;
}
// Spits out buttons based on the image supplied and
// whether a stroke or fill is to be defined
public JButton makeMeColorButton(String iconFile, final int actionNum,
final boolean stroke) {
JButton theBut = new JButton();
Icon butIcon = new ImageIcon(iconFile);
theBut.setIcon(butIcon);
theBut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (stroke) {
// JColorChooser is a popup that lets you pick a color
strokeColor = JColorChooser.showDialog(null,
"Pick a Stroke", Color.BLACK);
} else {
}
}
});
return theBut;
}
public class DrawingBoard extends JComponent {
Font textFont = new Font("Arial", Font.BOLD, 12);
private static final long serialVersionUID = -4431176095451940075L;
// ArrayLists that contain each shape drawn along with
// that shapes stroke and fill
ArrayList<Shape> shapes = new ArrayList<Shape>();
ArrayList<Color> shapeStroke = new ArrayList<Color>();
ArrayList<Integer> count = new ArrayList<Integer>();
Point drawStart, drawEnd;
// Monitors events on the drawing area of the frame
public DrawingBoard() {
this.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
if (currentAction != 1) {
// When the mouse is pressed get x & y position
drawStart = new Point(e.getX(), e.getY());
drawEnd = drawStart;
repaint();
}
}
public void mouseReleased(MouseEvent e) {
int counts =0;
if (currentAction != 1) {
Shape aShape = null;
if (currentAction == 2) {
aShape = drawLine(drawStart.x, drawStart.y,
e.getX(), e.getY());
shapes.add(aShape);
shapeStroke.add(strokeColor);
drawStart = null;
drawEnd = null;
repaint();
} else
if (currentAction == 3) {
aShape = drawEllipse(drawStart.x, drawStart.y,
e.getX(), e.getY());
shapes.add(aShape);
shapeStroke.add(strokeColor);
drawStart = null;
drawEnd = null;
repaint();
counts = counts+1;
count.add(counts);
int sizes = count.size();
System.out.println(sizes);
// new AttributeForm().setVisible(true);
} else
if (currentAction == 4) {
//draw the rectangle
aShape = drawRectangle(drawStart.x, drawStart.y,
e.getX(), e.getY());
shapes.add(aShape);
shapeStroke.add(strokeColor);
drawStart = null;
drawEnd = null;
String text = (String) JOptionPane.showInputDialog(DrawingBoard, "Enter name:");
while (text == null || text.isEmpty()) {
text = (String) JOptionPane.showInputDialog(DrawingBoard, "You must enter a valid name! Please try again:");
}
repaint();
//new EntityForm().setVisible(true);
}
// Add shapes, fills and colors to there ArrayLists
}
}
});
this.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent me) {
JTextField name = new JTextField(15);
super.mouseClicked(me);
for (Shape s : shapes) {
if (s.contains(me.getPoint())) {//check if mouse is clicked within shape
//we can either just print out the object class name
System.out.println("Clicked a "+s.getClass().getName());
//or check the shape class we are dealing with using instance of with nested if
if (s instanceof Rectangle2D) {
//create table
}
else if (s instanceof Ellipse2D) {
}
}
}
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
// If this is a brush have shapes go on the screen quickly
if (currentAction == 1) {
int x = e.getX();
int y = e.getY();
Shape aShape = null;
shapes.add(aShape);
shapeStroke.add(strokeColor);
// Add the transparency value
}
// Get the final x & y position after the mouse is dragged
drawEnd = new Point(e.getX(), e.getY());
repaint();
}
});
}
public void paint(Graphics g) {
final int width = getWidth();
final int height = getHeight();
final double size = Math.sqrt(width * height);
// Class used to define the shapes to be drawn
graphSettings = (Graphics2D) g;
// Antialiasing cleans up the jagged lines and defines rendering
// rules
graphSettings.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Defines the line width of the stroke
graphSettings.setStroke(new BasicStroke(4));
// Iterators created to cycle through strokes and fills
Iterator<Color> strokeCounter = shapeStroke.iterator();
for (Shape s : shapes) {
// Grabs the next stroke from the color arraylist
graphSettings.setPaint(strokeCounter.next());
graphSettings.draw(s);
}
// Guide shape used for drawing
if (drawStart != null && drawEnd != null) {
// Makes the guide shape transparent
graphSettings.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, 0.40f));
// Make guide shape gray for professional look
graphSettings.setPaint(Color.LIGHT_GRAY);
Shape aShape = null;
if (currentAction == 2) {
aShape = drawLine(drawStart.x, drawStart.y, drawEnd.x,
drawEnd.y);
} else
if (currentAction == 3) {
aShape = drawEllipse(drawStart.x, drawStart.y, drawEnd.x,
drawEnd.y);
} else
if (currentAction == 4) {
// Create a new rectangle using x & y coordinates
aShape = drawRectangle(drawStart.x, drawStart.y, drawEnd.x,
drawEnd.y);
//Add text inside the rectangle
g.setColor(Color.black);
Font textFont = this.textFont.deriveFont((float) size * (1 / 12f));
g.setFont(textFont);
FontMetrics textMetrics = g.getFontMetrics();
g.drawString(text, (width - textMetrics.stringWidth(text)) / 2, (textMetrics.getAscent() + (height - (textMetrics.getAscent() + textMetrics.getDescent())) / 2));
FontMetrics fm = g.getFontMetrics();
int fontAscent = fm.getAscent();
int stringX = Math.min(drawStart.x, drawEnd.x);
int stringY = Math.min(drawStart.y, drawEnd.y) + fontAscent;
g.drawString(text, stringX, stringY);
}
graphSettings.draw(aShape);
}
}
private Rectangle2D.Float drawRectangle(int x1, int y1, int x2, int y2) {
// Get the top left hand corner for the shape
// Math.min returns the points closest to 0
int x = Math.min(x1, x2);
int y = Math.min(y1, y2);
// Gets the difference between the coordinates and
int width = Math.abs(x1 - x2);
int height = Math.abs(y1 - y2);
return new Rectangle2D.Float(x, y, width, height);
}
private Ellipse2D.Float drawEllipse(int x1, int y1, int x2, int y2) {
int x = Math.min(x1, x2);
int y = Math.min(y1, y2);
int width = Math.abs(x1 - x2);
int height = Math.abs(y1 - y2);
return new Ellipse2D.Float(x, y, width, height);
}
private Line2D.Float drawLine(int x1, int y1, int x2, int y2) {
return new Line2D.Float(x1, y1, x2, y2);
}
public void drawString(String text,int stringX, int stringY){
}
}
}
EntityForm 是获取矩形名称的窗体。这是一个简单的形式 "Enter name:"
"CODE EDITED(3)"
试试这个:
public class MyCanvas extends JPanel {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.getContentPane().add(new MyCanvas(), BorderLayout.CENTER);
frame.setSize(400, 400);
frame.setMinimumSize(frame.getSize());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
Color rectColor;
Color textColor;
Font textFont;
String text;
{
rectColor = new Color(0x0060FF);
textColor = new Color(0x404000);
textFont = new Font("Arial", Font.BOLD, 12);
text = "Hello, World!";
}
@Override
public void paint(Graphics g) {
final int width = getWidth();
final int height = getHeight();
final double size = Math.sqrt(width * height);
//setup
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//rectangle
g.clearRect(0, 0, width, height);
g.setColor(Color.blue);
int s = (int) (size * (1 / 10d));
g.fillRoundRect(0, 0, width, height, s, s);
//text
g.setColor(Color.black);
Font textFont = this.textFont.deriveFont((float) size * (1 / 12f));
g.setFont(textFont);
FontMetrics textMetrics = g.getFontMetrics();
g.drawString(text, (width - textMetrics.stringWidth(text)) / 2, (textMetrics.getAscent() + (height - (textMetrics.getAscent() + textMetrics.getDescent())) / 2));
}
}
所以你有两个问题:
- 如何获取用户输入的文本
- 如何在矩形中绘制文本
获取文本
您的 EntityForm class 应该有某种访问器方法来获取文本字段本身或文本字段的值(即用户输入的文本)。
我假设它还有一个 "Okay" 按钮供用户在输入文本后单击?因此,您需要先保存对新 EntityForm 的引用,然后将事件处理程序添加到 "okay" 按钮,然后再将其设置为可见。
因此,例如:
final EntityForm ef = new EntityForm();
ef.getOkayButton().addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
String text = ef.getTextInput().getText();
// draw text code here...
}
});
ef.setVisible(true);
以上显然只是一个示例,因为我不知道 EntityForm class 的 API,但它应该足以让您继续。如果您需要更具体的答案,那么您还需要 post EntityForm 的代码。
但是,比使用 EntityForm class 更简单的选择是使用内置的 JOptionPane.showInputDialog() 方法。因此,您可以这样做,而不是调用 new EntityForm()
:
String text = (String) JOptionPane.showInputDialog(drawingBoard, "Enter name:");
// Note that if the user presses "cancel" then text will be null. Also,
// user may not have entered any text and pressed "okay", so text will be
// an empty string.
if (text == null || text.isEmpty()) {
text = "[unnamed]";
}
// Instead of substituting for an alternative string, you could show
// an error message and ask the user for a name again until a valid
// name is supplied.e.g.:
/*
while (text == null || text.isEmpty()) {
text = (String) JOptionPane.showInputDialog(drawingBoard, "You must enter a valid name! Please try again:");
}
*/
// draw text code here...
绘制文本
此处需要Graphics2d#drawString() 方法之一。查看 API 文档以获取更多详细信息和选项,但其要点是:
// get the size of the current font
FontMetrics fm = g.getFontMetrics();
int fontAscent = fm.getAscent();
// drawString co-ordinates specify the baseline of the text, so lets
// tell it to draw at fontAscent pixels below the top of the rectangle.
// Note that the user might have started dragging from any corner of the
// rectangle, so we need to determine which co-ordinates represent the
// top-left most point of the rectangle by looking for the lowest value:
int stringX = Math.min(drawStart.x, drawEnd.x);
int stringY = Math.min(drawStart.y, drawEnd.y) + fontAscent;
// To add n pixles of padding between the rectangle edge and the string,
// just add n to the numbers passed in to the drawString() method here:
g.drawString(text, stringX stringY);
请注意,上面的代码并未尝试确保文本适合矩形。为此,您需要使用 fm.stringWidth(text)
,然后决定是否要裁剪绘制的文本、缩放它或减小字体大小直到它适合(它可能永远不会这样做)。所有这些都超出了这个问题的范围。
编辑
最近更改代码后,您现在在绘制方法中绘制字符串时遇到问题。问题是您没有在任何地方保存 JOptionPane.showInputDialog 返回的字符串。它被分配给一个名为 text
的局部范围变量,然后被丢弃。 (请注意,这不是 class 级变量 text
,因为您通过再次为其指定类型来声明一个新的局部变量;即,您正在使用 String text = ...
。但这不是实际问题。事实上,您可以摆脱 class-level text
变量并在拖动矩形时停止绘制它;不需要它。)
正如您已经在 class 级变量中存储了一个形状列表,以便在每次调用 paint()
时重新绘制,您还需要存储一个要绘制的字符串列表以及绘制它们的点。所以你需要一个新的 class 来将字符串与点相关联:
class DrawnString {
private final String text;
private final Point position;
// Insert constructor and getter methods here
}
然后您还需要 DrawingBoard
中的 class 级列表来存储这些实例,就像您的形状列表一样:
private List<DrawnString> strings = new ArrayList<DrawnString>();
现在,回到您的 mouseReleased
方法,在从 JOptionPane 获取文本之后,但在调用 repaint()
之前,您应该将字符串及其位置添加到 DrawnStrings 列表中。
// Note that you need to do this BEFORE you set drawStart and drawEnd to
// null, so move the lines where that is done to below these lines:
int stringX = Math.min(drawStart.x, drawEnd.x);
int stringY = Math.min(drawStart.y, drawEnd.y);
// now it's safe to discard these points:
drawStart = null;
drawEnd = null;
// Now save the string and its position in the list so that it can be
// redrawn every time paint() is called:
strings.add(new DrawnString(text, new Point(stringX, stringY)));
// Now we can call repaint():
repaint();
最后,在您的 paint()
方法中,绘制完所有形状后(即,在 for (Shape s : shapes)
循环之后),您应该绘制字符串:
// This is where you need to get the size of the font
FontMetrics fm = graphSettings.getFontMetrics();
int fontAscent = fm.getAscent();
for (DrawnString s : strings) {
Point p = s.getPosition();
// Draw with 2px padding, for example:
graphSettings.drawString(s.getText(), p.x + 2, p.y + fontAscent + 2);
}
最后,在 paint()
方法的末尾,在 if (currentAction == 4) {...}
块内,去掉那里的绘制字符串内容(即 //Add text inside the rectangle
评论之后的所有内容)。
瞧瞧!