root / trunk / extensions / extSymbology / src / org / gvsig / symbology / fmap / symbols / SmartTextSymbol.java @ 39572
History | View | Annotate | Download (16 KB)
1 |
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
|
---|---|
2 |
*
|
3 |
* Copyright (C) 2005-8 IVER T.I. and Generalitat Valenciana.
|
4 |
*
|
5 |
* This program is free software; you can redistribute it and/or
|
6 |
* modify it under the terms of the GNU General Public License
|
7 |
* as published by the Free Software Foundation; either version 2
|
8 |
* of the License, or (at your option) any later version.
|
9 |
*
|
10 |
* This program is distributed in the hope that it will be useful,
|
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13 |
* GNU General Public License for more details.
|
14 |
*
|
15 |
* You should have received a copy of the GNU General Public License
|
16 |
* along with this program; if not, write to the Free Software
|
17 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA.
|
18 |
*
|
19 |
* For more information, contact:
|
20 |
*
|
21 |
* Generalitat Valenciana
|
22 |
* Conselleria d'Infraestructures i Transport
|
23 |
* Av. Blasco Ib??ez, 50
|
24 |
* 46010 VALENCIA
|
25 |
* SPAIN
|
26 |
*
|
27 |
* +34 963862235
|
28 |
* gvsig@gva.es
|
29 |
* www.gvsig.gva.es
|
30 |
*
|
31 |
* or
|
32 |
*
|
33 |
* IVER T.I. S.A
|
34 |
* Salamanca 50
|
35 |
* 46005 Valencia
|
36 |
* Spain
|
37 |
*
|
38 |
* +34 963163400
|
39 |
* dac@iver.es
|
40 |
*/
|
41 |
|
42 |
/* CVS MESSAGES:
|
43 |
*
|
44 |
* $Id: SmartTextSymbol.java 13953 2007-09-21 12:26:04Z jaume $
|
45 |
* $Log$
|
46 |
* Revision 1.6 2007-09-21 12:25:32 jaume
|
47 |
* cancellation support extended down to the IGeometry and ISymbol level
|
48 |
*
|
49 |
* Revision 1.5 2007/08/16 06:55:19 jvidal
|
50 |
* javadoc updated
|
51 |
*
|
52 |
* Revision 1.4 2007/08/13 11:36:50 jvidal
|
53 |
* javadoc
|
54 |
*
|
55 |
* Revision 1.3 2007/03/28 16:48:14 jaume
|
56 |
* *** empty log message ***
|
57 |
*
|
58 |
* Revision 1.2 2007/03/21 17:36:22 jaume
|
59 |
* *** empty log message ***
|
60 |
*
|
61 |
* Revision 1.1 2007/03/09 11:20:56 jaume
|
62 |
* Advanced symbology (start committing)
|
63 |
*
|
64 |
* Revision 1.1.2.8 2007/02/21 07:34:09 jaume
|
65 |
* labeling starts working
|
66 |
*
|
67 |
* Revision 1.1.2.7 2007/02/16 10:54:12 jaume
|
68 |
* multilayer splitted to multilayerline, multilayermarker,and multilayerfill
|
69 |
*
|
70 |
* Revision 1.1.2.6 2007/02/15 16:23:44 jaume
|
71 |
* *** empty log message ***
|
72 |
*
|
73 |
* Revision 1.1.2.5 2007/02/09 07:47:05 jaume
|
74 |
* Isymbol moved
|
75 |
*
|
76 |
* Revision 1.1.2.4 2007/02/08 07:36:38 jaume
|
77 |
* *** empty log message ***
|
78 |
*
|
79 |
* Revision 1.1.2.3 2007/02/06 16:54:36 jaume
|
80 |
* *** empty log message ***
|
81 |
*
|
82 |
* Revision 1.1.2.2 2007/02/06 16:47:35 jaume
|
83 |
* first steps, follows a line
|
84 |
*
|
85 |
* Revision 1.1.2.1 2007/02/02 16:21:24 jaume
|
86 |
* start commiting labeling stuff
|
87 |
*
|
88 |
* Revision 1.1 2007/01/24 17:58:22 jaume
|
89 |
* new features and architecture error fixes
|
90 |
*
|
91 |
*
|
92 |
*/
|
93 |
package org.gvsig.symbology.fmap.symbols; |
94 |
|
95 |
import java.awt.BasicStroke; |
96 |
import java.awt.BorderLayout; |
97 |
import java.awt.Color; |
98 |
import java.awt.Dimension; |
99 |
import java.awt.Font; |
100 |
import java.awt.Graphics; |
101 |
import java.awt.Graphics2D; |
102 |
import java.awt.Rectangle; |
103 |
import java.awt.Shape; |
104 |
import java.awt.Stroke; |
105 |
import java.awt.event.ActionEvent; |
106 |
import java.awt.event.ActionListener; |
107 |
import java.awt.font.FontRenderContext; |
108 |
import java.awt.font.GlyphVector; |
109 |
import java.awt.font.LineMetrics; |
110 |
import java.awt.geom.AffineTransform; |
111 |
import java.util.ArrayList; |
112 |
|
113 |
import javax.print.attribute.PrintRequestAttributeSet; |
114 |
import javax.swing.JCheckBox; |
115 |
import javax.swing.JFrame; |
116 |
import javax.swing.JPanel; |
117 |
import javax.swing.JTextField; |
118 |
|
119 |
import org.gvsig.gui.beans.swing.GridBagLayoutPanel; |
120 |
import org.gvsig.gui.beans.swing.JComboBoxFonts; |
121 |
import org.gvsig.gui.beans.swing.JIncrementalNumberField; |
122 |
import org.gvsig.symbology.fmap.labeling.placements.PointPlacementConstraints; |
123 |
|
124 |
import com.iver.cit.gvsig.fmap.ViewPort; |
125 |
import com.iver.cit.gvsig.fmap.core.FPolygon2D; |
126 |
import com.iver.cit.gvsig.fmap.core.FPolyline2D; |
127 |
import com.iver.cit.gvsig.fmap.core.FShape; |
128 |
import com.iver.cit.gvsig.fmap.core.GeneralPathX; |
129 |
import com.iver.cit.gvsig.fmap.core.IGeometry; |
130 |
import com.iver.cit.gvsig.fmap.core.SymbologyFactory; |
131 |
import com.iver.cit.gvsig.fmap.core.TextPath; |
132 |
import com.iver.cit.gvsig.fmap.core.symbols.IFillSymbol; |
133 |
import com.iver.cit.gvsig.fmap.core.symbols.ITextSymbol; |
134 |
import com.iver.cit.gvsig.fmap.core.symbols.SimpleTextSymbol; |
135 |
import com.iver.cit.gvsig.fmap.core.symbols.SymbolDrawingException; |
136 |
import com.iver.cit.gvsig.fmap.core.v02.FConstant; |
137 |
import com.iver.cit.gvsig.fmap.rendering.styling.labeling.IPlacementConstraints; |
138 |
import com.iver.utiles.XMLEntity; |
139 |
import com.iver.utiles.swing.JComboBox; |
140 |
import com.iver.utiles.swing.threads.Cancellable; |
141 |
|
142 |
/**
|
143 |
* Class used to create symbols composed using a text defined by
|
144 |
* the user.This text can be edited (changing the color, the font of the characters, and
|
145 |
* the rotation of the text)and has the property that can follow a path.If this path
|
146 |
* does not exist, the text is treated as a simpletextsymbol (when is drawn).
|
147 |
* @author jaume dominguez faus - jaume.dominguez@iver.es
|
148 |
*/
|
149 |
public class SmartTextSymbol extends SimpleTextSymbol implements ITextSymbol { |
150 |
|
151 |
private char[] charText; |
152 |
// Background: ITextBackground
|
153 |
// Case
|
154 |
private double characterSpacing; |
155 |
private double characterWidth; |
156 |
// Direction
|
157 |
private IFillSymbol fillSymbol;
|
158 |
private double flipAngle; |
159 |
// boolean kerning;
|
160 |
private double leading; |
161 |
// Position: textPosition
|
162 |
private Color ShadowColor; |
163 |
private double ShadowXOffset; |
164 |
private double ShadowYOffset; |
165 |
// TypeSetting: Boolean
|
166 |
private double wordSpacing; |
167 |
// ISimpleTextSymbol : ITextSymbol
|
168 |
// BreakCharacter: Long
|
169 |
// Clip: Boolean
|
170 |
private TextPath textPath;
|
171 |
private double xOffset; |
172 |
private double yOffset; |
173 |
private double angle; |
174 |
// Color: IColor
|
175 |
|
176 |
// HorizontalAlignment:
|
177 |
// esriTextHorizontalAlignment
|
178 |
private boolean rightToLeft; |
179 |
// VerticalAlignment
|
180 |
private double maskSize; |
181 |
// MaskStyle
|
182 |
private IFillSymbol maskSymbol;
|
183 |
private double margin; |
184 |
private int alignment; |
185 |
private boolean kerning = false; |
186 |
private TextPath tp;
|
187 |
private IPlacementConstraints constraints;
|
188 |
|
189 |
public SmartTextSymbol(ITextSymbol sym, IPlacementConstraints constraints) {
|
190 |
|
191 |
if(sym instanceof SimpleTextSymbol){ |
192 |
SimpleTextSymbol mySym = (SimpleTextSymbol)sym; |
193 |
|
194 |
this.setAutoresizeEnabled(mySym.isAutoresizeEnabled());
|
195 |
this.setDescription(mySym.getDescription());
|
196 |
this.setFont(mySym.getFont());
|
197 |
this.setFontSize(mySym.getFont().getSize());
|
198 |
this.setIsShapeVisible(mySym.isShapeVisible());
|
199 |
this.setReferenceSystem(mySym.getReferenceSystem());
|
200 |
this.setRotation(mySym.getRotation());
|
201 |
this.setText(mySym.getText());
|
202 |
this.setTextColor(mySym.getTextColor());
|
203 |
this.setUnit(mySym.getUnit());
|
204 |
super.setText(this.getText()); |
205 |
this.constraints = constraints;
|
206 |
|
207 |
setCharacterSpacing(2); //??? |
208 |
setWordSpacing(TextPath.DEFAULT_WORD_SPACING); |
209 |
boolean rtl = false; // right to left text |
210 |
if (constraints.isAtTheBeginingOfLine()) {
|
211 |
if (rtl) {
|
212 |
setAlignment(FConstant.SYMBOL_STYLE_TEXTALIGNMENT_RIGHT); |
213 |
} |
214 |
else {
|
215 |
setAlignment(FConstant.SYMBOL_STYLE_TEXTALIGNMENT_LEFT); |
216 |
} |
217 |
} |
218 |
else if (constraints.isAtTheEndOfLine()) { |
219 |
if (rtl) {
|
220 |
setAlignment(FConstant.SYMBOL_STYLE_TEXTALIGNMENT_LEFT); |
221 |
} |
222 |
else {
|
223 |
setAlignment(FConstant.SYMBOL_STYLE_TEXTALIGNMENT_RIGHT); |
224 |
} |
225 |
} |
226 |
else { //constraints.isInTheMiddleOfLine() or constraints.isAtBestOfLine() |
227 |
setAlignment(FConstant.SYMBOL_STYLE_TEXTALIGNMENT_CENTERED); |
228 |
} |
229 |
setKerning(false);
|
230 |
setRightToLeft(rtl); |
231 |
} |
232 |
} |
233 |
public SmartTextSymbol() {
|
234 |
PointPlacementConstraints pc = new PointPlacementConstraints();
|
235 |
this.constraints = pc;
|
236 |
|
237 |
} |
238 |
|
239 |
/**
|
240 |
* Draws the text according. If this symbol has the text path set, then
|
241 |
* it is used as the text line, otherwise shp <b>must be an FPoint2D</b>
|
242 |
* indicating the starting point of the text and then the text will
|
243 |
* be rendered from there and following the rotation previously set.
|
244 |
*/
|
245 |
@Override
|
246 |
public void draw(Graphics2D g, AffineTransform affineTransform, FShape shp, Cancellable cancel) { |
247 |
if (!isShapeVisible()) return; |
248 |
|
249 |
setMargin(0);
|
250 |
|
251 |
|
252 |
tp = new TextPath(g, shp, charText, getFont(),
|
253 |
(float) characterSpacing, (float) characterWidth, kerning, |
254 |
(float) leading, alignment, (float) wordSpacing, (float) margin, rightToLeft); |
255 |
Font font = getFont();
|
256 |
g.setFont(font); |
257 |
FontRenderContext frc = g.getFontRenderContext();
|
258 |
LineMetrics lineMetrics = font.getLineMetrics(getText(), frc);
|
259 |
|
260 |
// GlyphVector glyph = font.layoutGlyphVector(frc, charText, 0, charText.length, Font.LAYOUT_NO_START_CONTEXT);
|
261 |
double cons = 0; |
262 |
|
263 |
/* Repartimos el leading (espacio de separaci?n entre lineas)
|
264 |
* arriba y abajo para que exista la misma separaci?n entre la
|
265 |
* caja de la letra y la linea tanto si se dibuja por abajo como
|
266 |
* si se dibuja por arriba.
|
267 |
*/
|
268 |
if(this.constraints.isAboveTheLine()) { |
269 |
cons = lineMetrics.getDescent()+lineMetrics.getLeading()/2;
|
270 |
} |
271 |
else if (this.constraints.isBelowTheLine()) { |
272 |
cons = -(lineMetrics.getAscent()+lineMetrics.getLeading()/2);
|
273 |
} |
274 |
/* Dibujamos la letra de tal manera que el centro de la caja de letra
|
275 |
* coincida con la linea
|
276 |
*/
|
277 |
else if(this.constraints.isOnTheLine()) { |
278 |
// cons = lineMetrics.getDescent()+(lineMetrics.getLeading()/2)-(lineMetrics.getHeight()/2);
|
279 |
cons = lineMetrics.getDescent()+lineMetrics.getLeading()-(lineMetrics.getHeight()/2);
|
280 |
} |
281 |
|
282 |
double[] coords = tp.nextPosForGlyph(0); |
283 |
Stroke haloStroke = new BasicStroke(getHaloWidth(), BasicStroke.CAP_ROUND, |
284 |
BasicStroke.JOIN_ROUND);
|
285 |
|
286 |
for (int i = 0; i < tp.getGlyphCount(); i++) { |
287 |
coords = tp.nextPosForGlyph(i); |
288 |
if (coords[0] == TextPath.NO_POS || coords[1] == TextPath.NO_POS) |
289 |
continue;
|
290 |
|
291 |
// move the label 'cons" units above/below the line
|
292 |
double xOffset = cons * Math.sin(coords[2]); |
293 |
double yOffset = cons * Math.cos(coords[2]); |
294 |
|
295 |
g.translate(coords[0]+xOffset, coords[1]-yOffset); |
296 |
g.rotate(coords[2]);
|
297 |
|
298 |
char[] aux = new char[1]; |
299 |
aux[0] = charText[i];
|
300 |
if (isDrawWithHalo()) {
|
301 |
GlyphVector glyph = font.createGlyphVector(frc, aux);
|
302 |
Shape outlineChar = glyph.getOutline();
|
303 |
g.setStroke(haloStroke); |
304 |
g.setColor(getHaloColor()); |
305 |
g.draw(outlineChar); |
306 |
} |
307 |
|
308 |
g.setColor(this.getTextColor());
|
309 |
g.drawString(String.valueOf(charText[i]), 0, 0); |
310 |
g.rotate(-coords[2]);
|
311 |
g.translate(-coords[0]-xOffset, -coords[1]+yOffset); |
312 |
} |
313 |
} |
314 |
|
315 |
@Override
|
316 |
public void getPixExtentPlus(FShape shp, float[] distances, ViewPort viewPort, int dpi) { |
317 |
// TODO Implement it
|
318 |
throw new Error("Not yet implemented!"); |
319 |
|
320 |
} |
321 |
|
322 |
@Override
|
323 |
public int getOnePointRgb() { |
324 |
return getTextColor().getRGB();
|
325 |
} |
326 |
|
327 |
@Override
|
328 |
public XMLEntity getXMLEntity() {
|
329 |
XMLEntity xml = new XMLEntity();
|
330 |
xml.putProperty("className", getClassName());
|
331 |
xml.putProperty("desc", getDescription());
|
332 |
xml.putProperty("isShapeVisible", isShapeVisible());
|
333 |
return xml;
|
334 |
} |
335 |
|
336 |
@Override
|
337 |
public int getSymbolType() { |
338 |
return FShape.TEXT;
|
339 |
} |
340 |
|
341 |
@Override
|
342 |
public boolean isSuitableFor(IGeometry geom) { |
343 |
return (geom.getGeometryType()%FShape.Z) == FShape.LINE;
|
344 |
} |
345 |
|
346 |
@Override
|
347 |
public void drawInsideRectangle(Graphics2D g, AffineTransform scaleInstance, Rectangle r, PrintRequestAttributeSet properties) throws SymbolDrawingException { |
348 |
// let's take the bottom segment of the rectangle as the line
|
349 |
|
350 |
GeneralPathX gpx = new GeneralPathX();
|
351 |
gpx.moveTo(r.getX(), r.getY()); |
352 |
gpx.lineTo(r.getX()+r.getWidth(), r.getY()); |
353 |
if (properties==null) |
354 |
draw(g, scaleInstance, new FPolygon2D(gpx), null); |
355 |
else
|
356 |
print(g, scaleInstance, new FPolygon2D(gpx), properties);
|
357 |
|
358 |
} |
359 |
|
360 |
@Override
|
361 |
public String getClassName() { |
362 |
return getClass().getName();
|
363 |
} |
364 |
|
365 |
@Override
|
366 |
public void setXMLEntity(XMLEntity xml) { |
367 |
setFont(new Font("Arial", Font.PLAIN, 18)); |
368 |
setText("this is my TEST text that follows a line");
|
369 |
setDescription(xml.getStringProperty("desc"));
|
370 |
setIsShapeVisible(xml.getBooleanProperty("isShapeVisible"));
|
371 |
|
372 |
} |
373 |
|
374 |
@Override
|
375 |
public void setText(String text) { |
376 |
this.charText = text.toCharArray();
|
377 |
} |
378 |
|
379 |
@Override
|
380 |
public String getText() { |
381 |
return new String(charText); |
382 |
} |
383 |
|
384 |
public void setCharacterSpacing(double charSpacing) { |
385 |
this.characterSpacing = charSpacing;
|
386 |
} |
387 |
|
388 |
public void setWordSpacing(double wordSpacing) { |
389 |
this.wordSpacing = wordSpacing;
|
390 |
} |
391 |
|
392 |
public void setAlignment(int alignment) { |
393 |
this.alignment = alignment;
|
394 |
} |
395 |
|
396 |
public void setKerning(boolean kerning) { |
397 |
this.kerning = kerning;
|
398 |
} |
399 |
|
400 |
public void setMargin(double margin) { |
401 |
this.margin = margin;
|
402 |
} |
403 |
|
404 |
public void setRightToLeft(boolean rightToLeft) { |
405 |
this.rightToLeft = rightToLeft;
|
406 |
} |
407 |
|
408 |
public static void main(String[] args) { |
409 |
class Item { |
410 |
int value;
|
411 |
String text;
|
412 |
public Item(int value, String text) { |
413 |
this.value = value;
|
414 |
this.text = text;
|
415 |
} |
416 |
@Override
|
417 |
public String toString() { |
418 |
return text;
|
419 |
} |
420 |
|
421 |
public int getValue() { |
422 |
return value;
|
423 |
} |
424 |
} |
425 |
|
426 |
final int initialWidth = 300; |
427 |
final int initialHeight = 300; |
428 |
|
429 |
final JTextField textField = new JTextField("write your text here"); |
430 |
final JIncrementalNumberField textFontSize = new JIncrementalNumberField(); |
431 |
textFontSize.setDouble(15);
|
432 |
final JIncrementalNumberField textCharSpacing = new JIncrementalNumberField(); |
433 |
textCharSpacing.setDouble(1);
|
434 |
final JIncrementalNumberField textWordSpacing = new JIncrementalNumberField(); |
435 |
textCharSpacing.setDouble(10);
|
436 |
final JCheckBox chkKerning = new JCheckBox("Kerning:"); |
437 |
final JCheckBox chkRightToLeft = new JCheckBox("Rigth to left:"); |
438 |
final JComboBoxFonts cmbFonts = new JComboBoxFonts(); |
439 |
|
440 |
ArrayList<Integer> alignments = new ArrayList<Integer>(); |
441 |
final JComboBox cmbAlign = new JComboBox(new Item[] { |
442 |
new Item(FConstant.SYMBOL_STYLE_TEXTALIGNMENT_LEFT, "LEFT"), |
443 |
new Item(FConstant.SYMBOL_STYLE_TEXTALIGNMENT_RIGHT, "RIGHT"), |
444 |
new Item(FConstant.SYMBOL_STYLE_TEXTALIGNMENT_CENTERED, "CENTER"), |
445 |
new Item(FConstant.SYMBOL_STYLE_TEXTALIGNMENT_JUSTIFY, "JUSTIFY"), |
446 |
}); |
447 |
|
448 |
final JIncrementalNumberField txtMargin = new JIncrementalNumberField(); |
449 |
txtMargin.setDouble(10);
|
450 |
|
451 |
|
452 |
|
453 |
final JFrame f = new JFrame("test Smart Text Symbol"); |
454 |
JPanel content = new JPanel(new BorderLayout(20,20)); |
455 |
GridBagLayoutPanel controlPanel = new GridBagLayoutPanel();
|
456 |
controlPanel.addComponent("Text: ", textField);
|
457 |
controlPanel.addComponent("Font: ", cmbFonts);
|
458 |
controlPanel.addComponent("Font size: ", textFontSize);
|
459 |
controlPanel.addComponent("Char spacing: ", textCharSpacing);
|
460 |
controlPanel.addComponent("Word spacing: ", textWordSpacing);
|
461 |
controlPanel.addComponent("Alignment: ", cmbAlign);
|
462 |
controlPanel.addComponent("Margin: ", txtMargin);
|
463 |
controlPanel.addComponent(chkKerning); |
464 |
controlPanel.addComponent(chkRightToLeft); |
465 |
|
466 |
content.add(controlPanel, BorderLayout.NORTH);
|
467 |
|
468 |
final JPanel canvas = new JPanel() { |
469 |
private static final long serialVersionUID = 623038680274774722L; |
470 |
|
471 |
@Override
|
472 |
protected void paintComponent(Graphics g) { |
473 |
Graphics2D g2 = (Graphics2D) g; |
474 |
double width = getBounds().getWidth();
|
475 |
double height= getBounds().getHeight();
|
476 |
GeneralPathX gpx = new GeneralPathX();
|
477 |
|
478 |
gpx.moveTo(50, 100); |
479 |
gpx.lineTo(100, 50); |
480 |
gpx.lineTo(150, 100); |
481 |
gpx.lineTo(250, 50); |
482 |
|
483 |
SmartTextSymbol sms = new SmartTextSymbol();
|
484 |
FPolyline2D theLineShape = new FPolyline2D(gpx);
|
485 |
SymbologyFactory.createDefaultLineSymbol().draw(g2, null, theLineShape, null); |
486 |
sms.setFont(new Font((String) cmbFonts.getSelectedItem(), Font.PLAIN, 10)); |
487 |
sms.setFontSize(textFontSize.getDouble()); |
488 |
sms.setText(textField.getText()); |
489 |
sms.setCharacterSpacing(textCharSpacing.getDouble()); |
490 |
sms.setWordSpacing(textWordSpacing.getDouble()); |
491 |
sms.setAlignment(((Item) cmbAlign.getSelectedItem()).getValue()); |
492 |
sms.setKerning(chkKerning.isSelected()); |
493 |
sms.setRightToLeft(chkRightToLeft.isSelected()); |
494 |
sms.setMargin(txtMargin.getDouble()); |
495 |
sms.draw(g2, null, theLineShape, null); |
496 |
} |
497 |
}; |
498 |
|
499 |
ActionListener action = new ActionListener() { |
500 |
public void actionPerformed(ActionEvent e) { |
501 |
f.repaint(); |
502 |
} |
503 |
}; |
504 |
textFontSize.addActionListener(action); |
505 |
textCharSpacing.addActionListener(action); |
506 |
textWordSpacing.addActionListener(action); |
507 |
cmbAlign.addActionListener(action); |
508 |
txtMargin.addActionListener(action); |
509 |
chkKerning.addActionListener(action); |
510 |
chkRightToLeft.addActionListener(action); |
511 |
cmbFonts.addActionListener(action); |
512 |
|
513 |
|
514 |
canvas.setPreferredSize(new Dimension(initialWidth, initialHeight)); |
515 |
canvas.setSize(new Dimension(initialWidth, initialHeight)); |
516 |
content.add(canvas, BorderLayout.CENTER);
|
517 |
f.setContentPane(content); |
518 |
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
519 |
|
520 |
|
521 |
f.pack(); |
522 |
f.setVisible(true);
|
523 |
} |
524 |
|
525 |
} |