title: Are there better alternatives to g.drawString() / g2D.drawString()? (solved)
body: <p>I have been trying to put text onto an already existing window for a while now.
  I want to be able to add, remove, arrange and rearrange paragraphs across the screen.</p>
  <p>At first I tried to add text components - which had a delay of several seconds.
  Next I experimented with geometry in the paint component of JPanel-derivate, was delighted at how everything appeared instantly, and fell for a delusion that text would behave the same. But when I tried the drawString() method, I was met with a similar delay as before.
  Maybe this is a problem with my computer specifically and doesn't happen elsewhere.
  I would still like to remedy it though.</p>
  <p>Eventually I wrote this monstrosity:</p>
  <pre><code>import java.awt.geom.Area;
  import java.awt.geom.GeneralPath;
  import java.awt.geom.Line2D;
  import java.awt.geom.QuadCurve2D;
  import java.awt.geom.CubicCurve2D;
  import java.awt.geom.AffineTransform;
  
  import java.awt.Toolkit;
  import java.awt.Graphics;
  import java.awt.Graphics2D;
  import java.awt.Color;
  import java.awt.RenderingHints;
  import javax.swing.JFrame;
  import javax.swing.JPanel;
  
  class MainClass
  {
      public static void main(String[] args)
      {
          Schrift arabic = new Schrift(1368, 680, new Letter[] {
          new Letter('0', new int[][][] {{{361, 1385, 134, 1385, 52, 1145, 52, 915}, {52, 915, 52, 702, 134, 443, 361, 443}, {361, 443}, {363, 443, 588, 443, 669, 689, 669, 914}, {669, 914, 669, 1126, 588, 1385, 361, 1385}}}, new int [][][] {{{363, 1334, 236, 1334, 197, 1113, 197, 912}, {197, 912, 197, 710, 230, 494, 360, 494}, {360, 494}, {361, 494, 489, 494, 524, 707, 524, 912}, {524, 912, 524, 1116, 491, 1334, 363, 1334}}}, 722, new int[][] {}),
          new Letter('1', new int[][][] {{{580, 1368, 162, 1368}, {162, 1368, 162, 1326}, {162, 1326, 294, 1317, 303, 1302, 303, 1196}, {303, 1196, 303, 644}, {303, 644, 303, 568, 297, 561, 235, 557}, {235, 557, 157, 554}, {157, 554, 157, 519}, {157, 519, 225, 503, 347, 475, 437, 443}, {437, 443, 437, 1196}, {437, 1196, 437, 1302, 447, 1317, 580, 1326}, {580, 1326, 580, 1368}}}, new int[][][] {}, 722, new int[][] {}),
          new Letter('2', new int[][][] {{{612, 1368, 48, 1368}, {48, 1368, 48, 1333}, {48, 1333, 130, 1253, 216, 1171, 288, 1087}, {288, 1087, 380, 981, 472, 863, 472, 739}, {472, 739, 472, 619, 408, 548, 300, 548}, {300, 548, 198, 548, 135, 627, 95, 686}, {95, 686, 60, 654}, {60, 654, 149, 530}, {149, 530, 197, 481, 267, 443, 352, 443}, {352, 443, 488, 443, 607, 538, 607, 692}, {607, 692, 607, 817, 552, 900, 409, 1045}, {409, 1045, 204, 1251}, {204, 1251, 475, 1251}, {475, 1251, 558, 1251, 575, 1247, 622, 1152}, {622, 1152, 666, 1166}, {666, 1166, 645, 1233, 629, 1302, 612, 1368}}}, new int[][][] {}, 722, new int[][] {}),
          new Letter('3', new int[][][] {{{248, 1385, 178, 1385, 115, 1355, 93, 1334}, {93, 1334, 71, 1316, 66, 1298, 68, 1279}, {68, 1279, 70, 1260, 90, 1238, 105, 1228}, {105, 1228, 117, 1218, 130, 1218, 143, 1228}, {143, 1228, 179, 1260, 245, 1308, 331, 1308}, {331, 1308, 431, 1308, 503, 1233, 503, 1090}, {503, 1090, 503, 956, 399, 903, 316, 903}, {316, 903, 283, 903, 246, 911, 223, 918}, {223, 918, 214, 874}, {214, 874, 347, 832, 446, 777, 446, 672}, {446, 672, 446, 581, 383, 536, 306, 536}, {306, 536, 224, 536, 165, 596, 127, 653}, {127, 653, 95, 622}, {95, 622, 162, 528}, {162, 528, 204, 481, 272, 443, 354, 443}, {354, 443, 355, 443}, {355, 443, 492, 443, 580, 526, 580, 637}, {580, 637, 580, 678, 565, 710, 536, 739}, {536, 739, 511, 761, 476, 788, 434, 816}, {434, 816, 434, 819}, {434, 819, 567, 842, 642, 934, 641, 1042}, {641, 1042, 641, 1284, 345, 1385, 248, 1385}}}, new int[][][] {}, 722, new int[][] {}),
          new Letter('4', new int[][][] {{{673, 1368, 278, 1368}, {278, 1368, 278, 1327}, {278, 1327, 411, 1316, 417, 1304, 417, 1208}, {417, 1208, 417, 1110}, {417, 1110, 29, 1110}, {29, 1110, 29, 1064}, {29, 1064, 178, 851, 328, 643, 479, 447}, {479, 447, 546, 447}, {546, 447, 546, 1037}, {546, 1037, 689, 1037}, {689, 1037, 689, 1110}, {689, 1110, 546, 1110}, {546, 1110, 546, 1209}, {546, 1209, 546, 1307, 554, 1316, 673, 1327}, {673, 1327, 673, 1368}}}, new int[][][] {{{417, 1037, 125, 1037}, {125, 1037, 226, 876, 322, 737, 414, 616}, {414, 616, 417, 616}, {417, 616, 417, 1037}}}, 722, new int[][] {}),
          new Letter('5', new int[][][] {{{252, 1385, 185, 1385, 122, 1356, 98, 1334}, {98, 1334, 76, 1313, 68, 1301, 71, 1282}, {71, 1282, 71, 1266, 86, 1243, 105, 1228}, {105, 1228, 119, 1218, 131, 1218, 146, 1230}, {146, 1230, 179, 1259, 242, 1310, 335, 1310}, {335, 1310, 456, 1310, 514, 1206, 514, 1100}, {514, 1100, 514, 970, 433, 880, 274, 880}, {274, 880, 210, 880, 153, 898, 118, 909}, {118, 909, 178, 461}, {178, 461, 613, 461}, {613, 461, 622, 472}, {622, 472, 581, 577}, {581, 577, 227, 577}, {227, 577, 188, 839}, {188, 839, 249, 816, 322, 793, 361, 793}, {361, 793, 551, 793, 650, 918, 650, 1039}, {650, 1039, 650, 1128, 607, 1209, 514, 1284}, {514, 1284, 433, 1346, 332, 1385, 252, 1385}}}, new int[][][] {}, 722, new int[][] {}),
          new Letter('6', new int[][][] {{{366, 1385, 188, 1385, 52, 1244, 52, 1020}, {52, 1020, 52, 701, 281, 536, 441, 481}, {441, 481, 501, 461, 580, 443, 638, 434}, {638, 434, 648, 482}, {648, 482, 600, 491, 540, 509, 487, 533}, {487, 533, 398, 574, 259, 666, 214, 867}, {214, 867, 313, 819}, {313, 819, 347, 804, 376, 794, 405, 794}, {405, 794, 568, 794, 677, 912, 677, 1064}, {677, 1064, 677, 1238, 546, 1385, 366, 1385}}}, new int[][][] {{{390, 1333, 274, 1333, 198, 1193, 198, 1017}, {198, 1017, 198, 983, 200, 943, 207, 916}, {207, 916, 242, 899, 288, 880, 342, 880}, {342, 880, 344, 880}, {344, 880, 473, 880, 539, 995, 539, 1117}, {539, 1117, 539, 1212, 503, 1333, 390, 1333}}}, 722, new int[][] {}),
          new Letter('7', new int[][][] {{{264, 1369, 146, 1385}, {146, 1385, 135, 1368}, {135, 1368, 296, 1123, 463, 823, 583, 577}, {583, 577, 259, 577}, {259, 577, 160, 577, 150, 590, 112, 686}, {112, 686, 68, 686}, {68, 686, 83, 597, 90, 523, 98, 461}, {98, 461, 677, 461}, {677, 461, 689, 478}, {689, 478, 548, 774, 406, 1069, 264, 1369}}}, new int[][][] {}, 722, new int[][] {}),
          new Letter('8', new int[][][] {{{357, 1385, 191, 1385, 66, 1294, 66, 1139}, {66, 1139, 66, 1072, 101, 1032, 133, 1002}, {133, 1002, 157, 979, 214, 941, 264, 912}, {264, 912, 169, 860, 102, 788, 102, 685}, {102, 685, 102, 560, 211, 443, 374, 443}, {374, 443, 376, 443}, {376, 443, 519, 443, 622, 541, 622, 660}, {622, 660, 622, 702, 607, 745, 578, 777}, {578, 777, 565, 791, 527, 823, 463, 865}, {463, 865, 568, 924, 660, 992, 660, 1120}, {660, 1120, 660, 1292, 488, 1385, 357, 1385}}}, new int[][][] {{{374, 1336, 373, 1336}, {373, 1336, 283, 1336, 194, 1265, 194, 1129}, {194, 1129, 194, 1049, 242, 978, 309, 935}, {309, 935, 430, 995, 530, 1053, 530, 1161}, {530, 1161, 530, 1270, 460, 1336, 374, 1336}}, {{418, 844, 310, 791, 224, 745, 224, 638}, {224, 638, 224, 565, 274, 493, 357, 493}, {357, 493, 358, 493}, {358, 493, 425, 493, 504, 544, 504, 669}, {504, 669, 504, 755, 465, 807, 418, 844}}}, 722, new int[][] {}),
          new Letter('9', new int[][][] {{{93, 1391, 84, 1346}, {84, 1346, 300, 1311, 462, 1161, 510, 948}, {510, 948, 414, 999}, {414, 999, 380, 1017, 352, 1023, 325, 1023}, {325, 1023, 163, 1023, 54, 908, 54, 755}, {54, 755, 54, 615, 168, 443, 364, 443}, {364, 443, 366, 443}, {366, 443, 556, 443, 666, 611, 666, 809}, {666, 809, 666, 1078, 511, 1265, 310, 1345}, {310, 1345, 233, 1374, 135, 1390, 93, 1391}}}, new int[][][] {{{390, 937, 267, 937, 192, 828, 192, 702}, {192, 702, 192, 615, 235, 494, 342, 494}, {342, 494, 344, 494}, {344, 494, 484, 494, 521, 669, 521, 801}, {521, 801, 521, 831, 520, 865, 516, 899}, {516, 899, 487, 919, 440, 937, 390, 937}}}, 722, new int[][] {}),
          new Letter(' ', new int[][][] {}, new int[][][] {}, 400, new int[][] {})});
          
          JFrame frame = new JFrame();
          PaintPanel canvas = new PaintPanel();
          canvas.setBackground(Color.WHITE);
          frame.setSize(Toolkit.getDefaultToolkit().getScreenSize());
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.add(canvas);
          frame.setBackground(Color.WHITE);
          frame.setVisible(true);
          
          canvas.painting = new Area[] {arabic.print(&quot; 0123456789&quot;,73.).ink};
          canvas.colours = new Color[] {Color.BLACK};
          canvas.freshup();
      }
  }
  
  class PaintPanel extends JPanel
  {
      Area[] painting = new Area[] {};
      Color[] colours = new Color[] {};
      public void paint(Graphics g)
      {
          Graphics2D g2D = (Graphics2D)g;
          g2D.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON));
          int jobs = painting.length;
          int task = 0;
          while (task &lt; jobs)
          {
              g2D.setColor(colours[task]);
              g2D.fill(painting[task]);
              task ++;
          }
      }
      public void freshup() {this.repaint();}
  }
  
  class Schrift
  {
      int ascent = 0;
      int descent = 0;
      Letter[] symbols = null;
      
      Schrift(int chosenAscent, int chosenDescent, Letter[] chosenSymbols)
      {
          ascent = chosenAscent;
          descent = chosenDescent;
          int cells = 0;
          int sample = 0;
          int fullset = chosenSymbols.length;
          while (sample &lt; fullset)
          {
              int id = (int)(chosenSymbols[sample].name);
              if (id &gt; cells) {cells = id;}
              sample ++;
          }
          cells ++;
          symbols = new Letter[cells];
          sample = 0;
          while (sample &lt; fullset)
          {
              symbols[(int)(chosenSymbols[sample].name)] = chosenSymbols[sample];
              sample ++;
          }
      }
      
      Double measure(String line, Double size)
      {
          Double dimension = 0.;
          int letters = line.length();
          int beispiel = (int)(line.charAt(0));
          int num = 1;
          while (num &lt;= letters)
          {
              if (beispiel &lt; symbols.length)
              {
                  Letter zeichen = symbols[beispiel];
                  if (zeichen != null) {dimension += Double.valueOf(zeichen.width);}
                  if (num &lt; letters)
                  {   beispiel = (int)(line.charAt(num));
                      if (zeichen != null &amp;&amp; beispiel &lt; zeichen.kerning.length)
                      {dimension += Double.valueOf(zeichen.kerning[beispiel]);}   }
              }
              num ++;
          }
          dimension *= (size / (ascent + descent));
          return dimension;
      }
      
      Schnipsel print(String line, Double size)
      {
          Area ink = new Area();
          Double dimension = 0.;
          AffineTransform placing = new AffineTransform();
          int letters = line.length();
          int beispiel = (int)(line.charAt(0));
          int num = 1;
          while (num &lt;= letters)
          {
              if (beispiel &lt; symbols.length)
              {
                  Letter zeichen = symbols[beispiel];
                  if (zeichen != null)
                  {
                      ink.add(new Area(placing.createTransformedShape(zeichen.form)));
                      dimension += Double.valueOf(zeichen.width);
                      placing.translate(zeichen.width, 0);
                  }
                  if (num &lt; letters)
                  {
                      beispiel = (int)(line.charAt(num));
                      if (zeichen != null &amp;&amp; beispiel &lt; zeichen.kerning.length)
                      {
                          Double kern = Double.valueOf(zeichen.kerning[beispiel]);
                          dimension += kern;
                          placing.translate(kern, 0);
                      }
                  }
              }
              num ++;     
          }
          AffineTransform shrink = new AffineTransform();
          Double scale = (size / (ascent + descent));
          shrink.scale(scale, scale);
          return new Schnipsel(ascent/scale, descent/scale, dimension/scale, new Area(shrink.createTransformedShape(ink)));
      }
  }
  
  class Letter
  {
      char name = ' ';
      Area form = null;
      int width = 0;
      int[] kerning = null;
      
      Letter(char chosenName, int[][][] outlines, int[][][] clearings, int chosenWidth, int[][] kerningChoice)
      {
          name = chosenName;
          form = new Area();
          AutoPath painter = new AutoPath();
          int toAdd = outlines.length;
          int spot = 0;
          while (spot &lt; toAdd)
          {
              form.add(new Area(painter.trace(outlines[spot])));
              spot ++;
          }
          int toRemove = clearings.length;
          spot = 0;
          while (spot &lt; toRemove)
          {
              form.subtract(new Area(painter.trace(clearings[spot])));
              spot ++;
          }
          width = chosenWidth;
          int partners = 0;
          int zeichen = 0;
          int fullset = kerningChoice.length;
          while (zeichen &lt; fullset)
          {
              if (kerningChoice[zeichen][0] &gt; partners) {partners = kerningChoice[zeichen][0];}
              zeichen ++;
          }
          partners ++;
          kerning = new int[partners];
          zeichen = 0;
          while (zeichen &lt; fullset)
          {
              kerning[kerningChoice[zeichen][0]] = kerningChoice[zeichen][1];
              zeichen ++;
          }
      }
  }
  
  class Schnipsel
  {
      Double ascent = null;
      Double descent = null;
      Double width = null;
      Area ink = null;
      
      Schnipsel(Double chosenAscent, Double chosenDescent, Double widthFound, Area shapes)
      {
          ascent = chosenAscent;
          descent = chosenDescent;
          width = widthFound;
          ink = shapes;
      }
  }
  
  class AutoPath
  {
      GeneralPath trace(int[][] line)
      {
          GeneralPath form = new GeneralPath();
          int arcs = line.length;
          int step = 0;
          while (step &lt; arcs)
          {
              int points = line[step].length / 2;
              if (points == 2)
              {form.append(new Line2D.Float(
                  line[step][0],line[step][1] ,
                  line[step][2],line[step][3]),true);}
              else if (points == 3)
              {form.append(new QuadCurve2D.Float(
                  line[step][0],line[step][1] ,
                  line[step][2],line[step][3] ,
                  line[step][4],line[step][5]),true);}
              else if (points == 4)
              {form.append(new CubicCurve2D.Float(
                  line[step][0],line[step][1] ,
                  line[step][2],line[step][3] ,
                  line[step][4],line[step][5] ,
                  line[step][6],line[step][7]),true);}
              step ++;
          }
          int end = arcs - 1;
          int last = line[end].length - 1;
          if (line[0][0] == line[end][last-1] &amp;&amp; line[0][1] == line[end][last]) {form.closePath();}
          return form;
      }
  }
  </code></pre>
  <p>… which works fine, but has the problem that I will need to transcribe all the geometric information from any font that I would want to use - thus I am not quite sure if I should keep building on it or if that would just be a waste of time.</p>
  <p>Update: Under a different Question I found the info that drawString() only needs a few seconds to load the font you are using when you draw your very first words. After that it apparently works (for practical purposes) instantly - I don't know why I never thought to check what would happen with the seconds line of text that I would ask the computer to draw.</p>