swing - Java (Graphics2D): triangle drawn by created Graphics2D not visible until second repaint -
i have following minimal code draw line arrow head:
package gui; import java.awt.graphics; import java.awt.graphics2d; import java.awt.polygon; import java.awt.renderinghints; import java.awt.geom.affinetransform; import java.awt.geom.line2d; import javax.swing.jpanel; public class statebtn extends jpanel { private static final long serialversionuid = -431114028667352251l; @override protected void paintcomponent(graphics g) { super.paintcomponent(g); // enable antialiasing graphics2d g2 = (graphics2d) g; g2.setrenderinghint(renderinghints.key_antialiasing, renderinghints.value_antialias_on); g2.setrenderinghint(renderinghints.key_interpolation, renderinghints.value_interpolation_bilinear); // draw arrow line2d.double line = new line2d.double(0, getheight()/2, 20, getheight()/2); drawarrowhead(g2, line); g2.draw(line); // if call repaint() here (like in answer below), works } private void drawarrowhead(graphics2d g2d, line2d.double line) { affinetransform tx = new affinetransform(); tx.settoidentity(); double angle = math.atan2(line.y2-line.y1, line.x2-line.x1); tx.translate(line.x2, line.y2); tx.rotate((angle-math.pi/2d)); polygon arrowhead = new polygon(); arrowhead.addpoint(0,5); arrowhead.addpoint(-5,-5); arrowhead.addpoint(5,-5); graphics2d g = (graphics2d) g2d.create(); g.settransform(tx); g.fill(arrowhead); g.dispose(); } }
it created this:
package gui; import java.awt.eventqueue; import javax.swing.jframe; import javax.swing.jpanel; import javax.swing.border.emptyborder; public class main extends jframe { private static final long serialversionuid = 4085389089535850911l; private jpanel contentpane; public static void main(string[] args) { eventqueue.invokelater(new runnable() { public void run() { try { main frame = new main(); frame.setvisible(true); } catch (exception e) { e.printstacktrace(); } } }); } public main() { setdefaultcloseoperation(jframe.exit_on_close); setsize(500, 500); setlocation(0, 0); contentpane = new jpanel(); contentpane.setborder(new emptyborder(5, 5, 5, 5)); setcontentpane(contentpane); contentpane.setlayout(null); statebtn statebtn = new statebtn(); statebtn.setbounds(200,200,35,35); contentpane.add(statebtn); } }
the line drawn arrow head invisible until call repaint(). problem element draggable one, have call repaint() twice every time position changed. make code more complex , gui laggy.
why can't arrow head drawn line? there no 1 can me?
you've not posted true mcve, it's impossible know doing wrong, there's no need kludge you've used in answer, re-call repaint()
within paintcomponent. if still need your own code, please post valid mcve, code can compile , run without modification. example of mean mcve, please read mcve link , @ example mcve i've posted in answer below.
having said this, understand swing graphics passive, meaning have program change state based on event, call repaint()
, suggests swing repaint manager call paint. there no guarantee painting occur, since repaint requests have "stacked", backing due many being called in short time, may ignored.
so in case, can use code , modify see how works. give jpanel mouseadapter -- class both mouselistener , mousemotionlistener, , in adapter set 2 point instance fields, p0 -- mouse pressed, , p1 -- mouse drags or releases. can set these fields , call repaint, , let painting methods use p0 , p1 draw arrow. mouse adapater so:
private class mymouse extends mouseadapter { private boolean settingmouse = false; @override public void mousepressed(mouseevent e) { if (e.getbutton() != mouseevent.button1) { return; } p0 = e.getpoint(); p1 = null; settingmouse = true; // drawing new arrow repaint(); } @override public void mousereleased(mouseevent e) { setp1(e); settingmouse = false; // no longer drawing new arrow } @override public void mousedragged(mouseevent e) { setp1(e); } private void setp1(mouseevent e) { if (settingmouse) { p1 = e.getpoint(); repaint(); } } }
and within painting code, i'd use code, modified make use p0 , p1 points:
@override protected void paintcomponent(graphics g) { super.paintcomponent(g); graphics2d g2 = (graphics2d) g; g2.setrenderinghint(renderinghints.key_antialiasing, renderinghints.value_antialias_on); g2.setrenderinghint(renderinghints.key_interpolation, renderinghints.value_interpolation_bilinear); if (p0 != null && p1 != null) { line2d.double line = new line2d.double(p0.x, p0.y, p1.x, p1.y); drawarrowhead(g2, line); g2.draw(line); } }
the whole shebang so:
import java.awt.*; import java.awt.event.mouseadapter; import java.awt.event.mouseevent; import java.awt.geom.*; import javax.swing.*; @suppresswarnings("serial") public class statebtn extends jpanel { // constants size jpanel private static final int pref_w = 800; private static final int pref_h = 650; private static final int ah_size = 5; // size of arrow head -- avoid "magic" // numbers! // our start , end points arrow private point p0 = null; private point p1 = null; public statebtn() { // create , add label tell user jlabel label = new jlabel("click mouse , drag"); label.setfont(new font(font.sans_serif, font.bold, 42)); label.setforeground(new color(0, 0, 0, 50)); setlayout(new gridbaglayout()); add(label); // add center // create our mouseadapater , use both mouselistener , // mousemotionlistener mymouse mymouse = new mymouse(); addmouselistener(mymouse); addmousemotionlistener(mymouse); } @override protected void paintcomponent(graphics g) { super.paintcomponent(g); graphics2d g2 = (graphics2d) g; g2.setrenderinghint(renderinghints.key_antialiasing, renderinghints.value_antialias_on); g2.setrenderinghint(renderinghints.key_interpolation, renderinghints.value_interpolation_bilinear); // if there points draw! if (p0 != null && p1 != null) { line2d.double line = new line2d.double(p0.x, p0.y, p1.x, p1.y); drawarrowhead(g2, line); g2.draw(line); } } private void drawarrowhead(graphics2d g2d, line2d.double line) { affinetransform tx = new affinetransform(); tx.settoidentity(); double angle = math.atan2(line.y2 - line.y1, line.x2 - line.x1); tx.translate(line.x2, line.y2); tx.rotate((angle - math.pi / 2d)); polygon arrowhead = new polygon(); arrowhead.addpoint(0, ah_size); // again avoid "magic" numbers arrowhead.addpoint(-ah_size, -ah_size); arrowhead.addpoint(ah_size, -ah_size); graphics2d g = (graphics2d) g2d.create(); g.settransform(tx); g.fill(arrowhead); g.dispose(); // created this, can dispose of // should **not** dispose of g2d since jvm gave } @override public dimension getpreferredsize() { // size our jpanel return new dimension(pref_w, pref_h); } private class mymouse extends mouseadapter { private boolean settingmouse = false; @override public void mousepressed(mouseevent e) { // if press wrong mouse button, exit if (e.getbutton() != mouseevent.button1) { return; } p0 = e.getpoint(); // set start point p1 = null; // clear end point settingmouse = true; // tell mouse listener we're creating new arrow repaint(); // suggest repaint } @override public void mousereleased(mouseevent e) { setp1(e); settingmouse = false; // no longer drawing new arrow } @override public void mousedragged(mouseevent e) { setp1(e); } private void setp1(mouseevent e) { if (settingmouse) { p1 = e.getpoint(); // set end point repaint(); // , paint! } } } public static void main(string[] args) { swingutilities.invokelater(() -> createandshowgui()); } private static void createandshowgui() { statebtn mainpanel = new statebtn(); jframe frame = new jframe("statebtn"); frame.setdefaultcloseoperation(jframe.exit_on_close); frame.add(mainpanel); frame.pack(); frame.setlocationrelativeto(null); frame.setvisible(true); } }
this code meant example of mcve. it's little large decent mcve, do. please compile , run code see works. if doesn't you, if still must use kludge repaint calls, urge create own mcve , post question, , comment me can see it.
an aside, questioned if ok create new graphics object you're doing within drawarrowhead(...)
method, , yes not ok, it's preferred thing when dealing affinetransforms, since way don't have worry down-stream effects transform might have on border , child components might share original graphics object. again ok, long follow rule of disposing graphics objects you create, , not disposing graphics objects given jvm.
Comments
Post a Comment