📄 treevisualizer.java
字号:
* 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 //from overlapping //it will leave the view centered int dist; Node ln,rn; Dimension temp = new Dimension(10, 10); if (m_numNodes <= 1) { return; } //calc height needed by first node dist = (m_nodes[0].m_height + 40) * m_numLevels; if (dist > temp.height) { temp.height = dist; } for (int noa = 0;noa < m_numNodes - 1;noa++) { calcScreenCoords(noa); calcScreenCoords(noa+1); if (m_nodes[noa+1].m_change) { //then on a new level so don't check width this time round } else { dist = m_nodes[noa+1].m_center - m_nodes[noa].m_center; //the distance between the node centers, along horiz if (dist <= 0) { dist = 1; } dist = ((6 + m_nodes[noa].m_side + m_nodes[noa+1].m_side) * m_viewSize.width) / dist; //calc optimal size for width
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -