📄 treevisualizer.java
字号:
}
else if (m_mouseState == 3) {
//then zoom box being created
//redraw the zoom box
Graphics g = getGraphics();
g.setColor(Color.black);
g.setXORMode(Color.white);
g.drawRect(m_oldMousePos.width, m_oldMousePos.height,
m_newMousePos.width - m_oldMousePos.width,
m_newMousePos.height - m_oldMousePos.height);
m_newMousePos.width = e.getX();
m_newMousePos.height = e.getY();
g.drawRect(m_oldMousePos.width, m_oldMousePos.height,
m_newMousePos.width - m_oldMousePos.width,
m_newMousePos.height - m_oldMousePos.height);
g.dispose();
}
}
/**
* Does nothing.
*
* @param e the mouse event.
*/
public void mouseMoved(MouseEvent e) {
}
/**
* Does nothing.
*
* @param e the mouse event.
*/
public void mouseEntered(MouseEvent e) {
}
/**
* Does nothing.
*
* @param e the mouse event.
*/
public void mouseExited(MouseEvent e) {
}
/**
* Set the highlight for the node with the given id
* @param id the id of the node to set the highlight for
*/
public void setHighlight(String id) {
//set the highlight for the node with the given id
for (int noa = 0; noa < m_numNodes; noa++) {
if (id.equals(m_nodes[noa].m_node.getRefer())) {
//then highlight this node
m_highlightNode = noa;
}
}
//System.out.println("ahuh " + highlight_node + " " +
//nodes[0].node.getRefer());
repaint();
}
/**
* Updates the screen contents.
*
* @param g the drawing surface.
*/
public void paintComponent(Graphics g) {
//System.out.println(nodes[0].top + "this is seriously pissing me off");
g.clearRect(0, 0, getSize().width, getSize().height);
g.setClip(3, 7, getWidth() - 6, getHeight() - 10);
painter(g);
g.setClip(0, 0, getWidth(), getHeight());
}
/**
* Draws the tree to the graphics context
*
* @param g the drawing surface.
*/
private void painter(Graphics g) {
//I have moved what would normally be in the paintComponent
//function to here
//for now so that if I do in fact need to do double
//buffering or the like it will be easier
//this will go through the table of edges and draw the edge if it deems the
//two nodes attached to it could cause it to cut the screen or be on it.
//in the process flagging all nodes so that they can quickly be put to the
//screen if they lie on it
//I do it in this order because in some circumstances I have seen a line
//cut through a node , to make things look better the line will
//be drawn under the node
//converting the screen edges to the node scale so that they
//can be positioned relative to the screen
//note I give a buffer around the edges of the screen.
//when seeing
//if a node is on screen I only bother to check the nodes top centre
//if it has large enough size it may still fall onto the screen
double left_clip = (double)(-m_viewPos.width - 50) / m_viewSize.width;
double right_clip = (double)(getSize().width - m_viewPos.width + 50) /
m_viewSize.width;
double top_clip = (double)(-m_viewPos.height - 50) / m_viewSize.height;
double bottom_clip = (double)(getSize().height - m_viewPos.height + 50) /
m_viewSize.height;
// 12 10 9 //the quadrants
// 20 18 17
// 36 34 33
//first the edges must be rendered
Edge e;
Node r,s;
double ncent,ntop;
int row = 0, col = 0, pq, cq;
for (int noa = 0 ; noa < m_numNodes ; noa++) {
r = m_nodes[noa].m_node;
if (m_nodes[noa].m_change) {
//then recalc row component of quadrant
ntop = r.getTop();
if (ntop < top_clip) {
row = 8;
}
else if (ntop > bottom_clip) {
row = 32;
}
else {
row = 16;
}
}
//calc the column the node falls in for the quadrant
ncent = r.getCenter();
if (ncent < left_clip) {
col = 4;
}
else if (ncent > right_clip) {
col = 1;
}
else {
col = 2;
}
m_nodes[noa].m_quad = row | col;
if (m_nodes[noa].m_parent >= 0) {
//this will draw the edge if it should be drawn
//It will do this by eliminating all edges that definitely won't enter
//the screen and then draw the rest
pq = m_nodes[m_edges[m_nodes[noa].m_parent].m_parent].m_quad;
cq = m_nodes[noa].m_quad;
//note that this will need to be altered if more than 1 parent exists
if ((cq & 8) == 8) {
//then child exists above screen
}
else if ((pq & 32) == 32) {
//then parent exists below screen
}
else if ((cq & 4) == 4 && (pq & 4) == 4) {
//then both child and parent exist to the left of the screen
}
else if ((cq & 1) == 1 && (pq & 1) == 1) {
//then both child and parent exist to the right of the screen
}
else {
//then draw the line
drawLine(m_nodes[noa].m_parent, g);
}
}
//now draw the nodes
}
for (int noa = 0 ;noa < m_numNodes; noa++) {
if (m_nodes[noa].m_quad == 18) {
//then the node is on the screen , draw it
drawNode(noa, g);
}
}
if (m_highlightNode >= 0 && m_highlightNode < m_numNodes) {
//then draw outline
if (m_nodes[m_highlightNode].m_quad == 18) {
Color acol = m_nodes[m_highlightNode].m_node.getColor();
g.setColor(new Color((acol.getRed() + 125) % 256,
(acol.getGreen() + 125) % 256,
(acol.getBlue() + 125) % 256));
//g.setXORMode(Color.white);
if (m_nodes[m_highlightNode].m_node.getShape() == 1) {
g.drawRect(m_nodes[m_highlightNode].m_center
- m_nodes[m_highlightNode].m_side,
m_nodes[m_highlightNode].m_top,
m_nodes[m_highlightNode].m_width,
m_nodes[m_highlightNode].m_height);
g.drawRect(m_nodes[m_highlightNode].m_center
- m_nodes[m_highlightNode].m_side
+ 1, m_nodes[m_highlightNode].m_top + 1,
m_nodes[m_highlightNode].m_width - 2,
m_nodes[m_highlightNode].m_height - 2);
}
else if (m_nodes[m_highlightNode].m_node.getShape() == 2) {
g.drawOval(m_nodes[m_highlightNode].m_center
- m_nodes[m_highlightNode].m_side,
m_nodes[m_highlightNode].m_top,
m_nodes[m_highlightNode].m_width,
m_nodes[m_highlightNode].m_height);
g.drawOval(m_nodes[m_highlightNode].m_center
- m_nodes[m_highlightNode].m_side
+ 1, m_nodes[m_highlightNode].m_top + 1,
m_nodes[m_highlightNode].m_width - 2,
m_nodes[m_highlightNode].m_height - 2);
}
}
}
for (int noa = 0;noa < m_numNodes;noa++) {
//this resets the coords so that next time a refresh occurs
//they don't accidentally get used
//I will use 32000 to signify that they are invalid, even if this
//coordinate occurs it doesn't
//matter as it is only for the sake of the caching
m_nodes[noa].m_top = 32000;
}
}
/**
* Determines the attributes of the node and draws it.
*
* @param n A subscript identifying the node in <i>nodes</i> array
* @param g The drawing surface
*/
private void drawNode(int n, Graphics g) {
//this will draw a node and then print text on it
g.setColor(m_nodes[n].m_node.getColor());
g.setPaintMode();
calcScreenCoords(n);
int x = m_nodes[n].m_center - m_nodes[n].m_side;
int y = m_nodes[n].m_top;
if (m_nodes[n].m_node.getShape() == 1) {
g.fill3DRect(x, y, m_nodes[n].m_width, m_nodes[n].m_height, true);
drawText(x, y, n, false, g);
}
else if (m_nodes[n].m_node.getShape() == 2) {
g.fillOval(x, y, m_nodes[n].m_width, m_nodes[n].m_height);
drawText(x, y + (int)(m_nodes[n].m_height * .15), n, false, g);
}
}
/**
* Determines the attributes of the edge and draws it.
*
* @param e A subscript identifying the edge in <i>edges</i> array.
* @param g The drawing surface.
*/
private void drawLine(int e, Graphics g) {
//this will draw a line taking in the edge number and then getting
//the nodes subscript for the parent and child entries
//this will draw a line that has been broken in the middle
//for the edge text to be displayed
//if applicable
//first convert both parent and child node coords to screen coords
int p = m_edges[e].m_parent;
int c = m_edges[e].m_child;
calcScreenCoords(c);
calcScreenCoords(p);
g.setColor(Color.black);
g.setPaintMode();
if (m_currentFont.getSize() < 2) {
//text to small to bother cutting the edge
g.drawLine(m_nodes[p].m_center, m_nodes[p].m_top + m_nodes[p].m_height,
m_nodes[c].m_center, m_nodes[c].m_top);
}
else {
//find where to cut the edge to insert text
int e_width = m_nodes[c].m_center - m_nodes[p].m_center;
int e_height = m_nodes[c].m_top - (m_nodes[p].m_top
+ m_nodes[p].m_height);
int e_width2 = e_width / 2;
int e_height2 = e_height / 2;
int e_centerx = m_nodes[p].m_center + e_width2;
int e_centery = m_nodes[p].m_top + m_nodes[p].m_height + e_height2;
int e_offset = m_edges[e].m_tb;
int tmp = (int)(((double)e_width / e_height) *
(e_height2 - e_offset)) + m_nodes[p].m_center;
//System.out.println(edges[e].m_height);
//draw text now
drawText(e_centerx - m_edges[e].m_side, e_centery - e_offset, e, true
, g);
if (tmp > (e_centerx - m_edges[e].m_side) && tmp
< (e_centerx + m_edges[e].m_side)) {
//then cut line on top and bottom of text
g.drawLine(m_nodes[p].m_center, m_nodes[p].m_top + m_nodes[p].m_height
, tmp, e_centery - e_offset); //first segment
g.drawLine(e_centerx * 2 - tmp, e_centery + e_offset,
m_nodes[c].m_center, m_nodes[c].m_top); //second segment
}
else {
e_offset = m_edges[e].m_side;
if (e_width < 0) {
e_offset *= -1; //adjusting for direction which could otherwise
//screw up the calculation
}
tmp = (int)(((double)e_height / e_width) * (e_width2 - e_offset)) +
m_nodes[p].m_top + m_nodes[p].m_height;
g.drawLine(m_nodes[p].m_center, m_nodes[p].m_top + m_nodes[p].m_height
, e_centerx - e_offset, tmp); //first segment
g.drawLine(e_centerx + e_offset, e_centery * 2 - tmp,
m_nodes[c].m_center, m_nodes[c].m_top); //second segment
}
}
//System.out.println("here" + nodes[p].center);
}
/**
* Draws the text for either an Edge or a Node.
*
* @param x1 the left side of the text area.
* @param y1 the top of the text area.
* @param s A subscript identifying either a Node or Edge.
* @param e_or_n Distinguishes whether it is a node or edge.
* @param g The drawing surface.
*/
private void drawText(int x1, int y1, int s, boolean e_or_n, Graphics g) {
//this function will take in the rectangle that the text should be
//drawn in as well as the subscript
//for either the edge or node and a boolean variable to tell which
g.setPaintMode();
g.setColor(Color.black);
String st;
if (e_or_n) {
//then paint for edge
Edge e = m_edges[s].m_edge;
for (int noa = 0;(st = e.getLine(noa)) != null; noa++) {
g.drawString(st, (m_edges[s].m_width - m_fontSize.stringWidth(st)) / 2
+ x1,
y1 + (noa + 1) * m_fontSize.getHeight());
}
}
else {
//then paint for node
Node e = m_nodes[s].m_node;
for (int noa = 0;(st = e.getLine(noa)) != null; noa++) {
g.drawString(st, (m_nodes[s].m_width - m_fontSize.stringWidth(st)) / 2
+ x1,
y1 + (noa + 1) * m_fontSize.getHeight());
}
}
}
/**
* Converts the internal coordinates of the node found from <i>n</i>
* and converts them to the actual screen coordinates.
*
* @param n A subscript identifying the Node.
*/
private void calcScreenCoords(int n) {
//this converts the coordinate system the Node uses into screen coordinates
// System.out.println(n + " " + view_pos.height + " " +
//nodes[n].node.getCenter());
if (m_nodes[n].m_top == 32000) {
m_nodes[n].m_top = ((int)(m_nodes[n].m_node.getTop()
* m_viewSize.height)) + m_viewPos.height;
m_nodes[n].m_center = ((int)(m_nodes[n].m_node.getCenter()
* m_viewSize.width)) + m_viewPos.width;
}
}
/**
* This Calculates the minimum size of the tree which will prevent any text
* overlapping and make it readable, and then set the size of the tree to
* this.
*/
private void autoScale() {
//this function will determine the smallest scale value that keeps the text
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -