下面列出了怎么用javax.swing.text.TabExpander的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* Draw text. This can directly call the Utilities.drawTabbedText.
* Sub-classes can override this method to provide any other decorations.
* @param segment - the source of the text
* @param x - the X origin >= 0
* @param y - the Y origin >= 0
* @param graphics - the graphics context
* @param e - how to expand the tabs. If this value is null, tabs will be
* expanded as a space character.
* @param startOffset - starting offset of the text in the document >= 0
* @return
*/
public int drawText(Segment segment, int x, int y,
Graphics graphics, TabExpander e, int startOffset) {
graphics.setFont(graphics.getFont().deriveFont(getFontStyle()));
FontMetrics fontMetrics = graphics.getFontMetrics();
int a = fontMetrics.getAscent();
int h = a + fontMetrics.getDescent();
int w = Utilities.getTabbedTextWidth(segment, fontMetrics, 0, e, startOffset);
int rX = x - 1;
int rY = y - a;
int rW = w + 2;
int rH = h;
if ((getFontStyle() & 0x10) != 0) {
graphics.setColor(Color.decode("#EEEEEE"));
graphics.fillRect(rX, rY, rW, rH);
}
graphics.setColor(getColor());
x = Utilities.drawTabbedText(segment, x, y, graphics, e, startOffset);
if ((getFontStyle() & 0x8) != 0) {
graphics.setColor(Color.RED);
graphics.drawRect(rX, rY, rW, rH);
}
return x;
}
/**
* Draw text. This can directly call the Utilities.drawTabbedText.
* Sub-classes can override this method to provide any other decorations.
* @param segment - the source of the text
* @param x - the X origin >= 0
* @param y - the Y origin >= 0
* @param graphics - the graphics context
* @param e - how to expand the tabs. If this value is null, tabs will be
* expanded as a space character.
* @param startOffset - starting offset of the text in the document >= 0
* @return
*/
public int drawText(Segment segment, int x, int y,
Graphics graphics, TabExpander e, int startOffset) {
graphics.setFont(graphics.getFont().deriveFont(getFontStyle()));
FontMetrics fontMetrics = graphics.getFontMetrics();
int a = fontMetrics.getAscent();
int h = a + fontMetrics.getDescent();
//JPEXS: UniTools for multi fonts
int w = UniTools.getTabbedTextWidth(graphics,segment,0, e, startOffset);
int rX = x - 1;
int rY = y - a;
int rW = w + 2;
int rH = h;
if ((getFontStyle() & 0x10) != 0) {
graphics.setColor(Color.decode("#EEEEEE"));
graphics.fillRect(rX, rY, rW, rH);
}
graphics.setColor(getColor());
//JPEXS: UniTools for multi fonts
x = UniTools.drawTabbedText(segment, x, y, graphics, e, startOffset);
if ((getFontStyle() & 0x8) != 0) {
graphics.setColor(Color.RED);
graphics.drawRect(rX, rY, rW, rH);
}
return x;
}
public static int getTabbedTextOffset(Segment segment, FontMetrics metrics, int tabBase,int x,TabExpander e, int startOffset){
List<Segment> segments=new ArrayList<Segment>();
List<Boolean> unis=new ArrayList<Boolean>();
Font origFont=metrics.getFont();
getSegments(origFont, segment, segments, unis);
Graphics g=new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB).getGraphics();
Font uniFont = defaultUniFont.deriveFont(origFont.getStyle(),origFont.getSize2D());
int ofs=0;
int totalto = 0;
for(int i=0;i<segments.size();i++){
Segment seg=segments.get(i);
FontMetrics fm=unis.get(i)?g.getFontMetrics(uniFont):metrics;
int to = Utilities.getTabbedTextOffset(seg, fm, tabBase+ofs,x, e, startOffset);
totalto += to;
ofs+=fm.stringWidth(seg.toString());
if(to<seg.length()){
break;
}
}
return totalto;
}
public static int drawTabbedText(Segment segment, int x, int y, Graphics g, TabExpander e, int startOffset){
List<Segment> segments=new ArrayList<Segment>();
List<Boolean> unis=new ArrayList<Boolean>();
getSegments(g.getFont(), segment, segments, unis);
Font origFont=g.getFont();
Font uniFont = defaultUniFont.deriveFont(origFont.getStyle(),origFont.getSize2D());
int ret=x;
int pos=0;
for(int i=0;i<segments.size();i++){
Segment seg=segments.get(i);
if(unis.get(i)){
g.setFont(uniFont);
}else{
g.setFont(origFont);
}
ret = Utilities.drawTabbedText(seg, ret, y, g, e, startOffset+pos);
pos += seg.length();
}
g.setFont(origFont);
return ret;
}
/**
* Determine the span the glyphs given a start location
* (for tab expansion).
* @param exp
* @return
*/
@Override
public float getSpan(GlyphView v, int p0, int p1,
TabExpander exp, float x) {
try {
sync(v);
String docText = v.getDocument().getText(p0,p1-p0);
float width = getTabbedTextWidth(v, docText, x, exp, p0, null);
return width;
} catch (BadLocationException e) {
//e.printStackTrace();
IOHandler.writeErrorLog(e, "EXTERNAL CODE");
}
return 0;
}
/**
* Determines the best location (in the model) to break
* the given view.
* This method attempts to break on a whitespace
* location. If a whitespace location can't be found, the
* nearest character location is returned.
*
* @param v the view
* @param p0 the location in the model where the
* fragment should start its representation >= 0
* @param x the graphic location along the axis that the
* broken view would occupy >= 0; this may be useful for
* things like tab calculations
* @param len specifies the distance into the view
* where a potential break is desired >= 0
* @return the model location desired for a break
* @see View#breakView
*/
@Override
public int getBoundedPosition(GlyphView v, int p0, float x, float len) {
int ret;
try {
sync(v);
TabExpander expander = v.getTabExpander();
String s = v.getDocument().getText(p0, v.getEndOffset()-p0);
int index = getTabbedTextOffset(v,s, (int)x, (int)(x+len), expander, p0, false, null);
int p1 = p0 + index;
ret = p1;
} catch (BadLocationException e) {
//e.printStackTrace();
ret = -1;
IOHandler.writeErrorLog(e, "EXTERNAL CODE");
}
return ret;
}
/**
* Draw text. This can directly call the Utilities.drawTabbedText.
* Sub-classes can override this method to provide any other decorations.
*
* @param segment - the source of the text
* @param x - the X origin >= 0
* @param y - the Y origin >= 0
* @param graphics - the graphics context
* @param e - how to expand the tabs. If this value is null, tabs will be
* expanded as a space character.
* @param startOffset - starting offset of the text in the document >= 0
* @return
*/
public int drawText(Segment segment, int x, int y,
Graphics graphics, TabExpander e, int startOffset) {
graphics.setFont(graphics.getFont().deriveFont(getFontStyle()));
FontMetrics fontMetrics = graphics.getFontMetrics();
int a = fontMetrics.getAscent();
int h = a + fontMetrics.getDescent();
int w = Utilities.getTabbedTextWidth(segment, fontMetrics, 0, e, startOffset);
int rX = x - 1;
int rY = y - a;
int rW = w + 2;
int rH = h;
if ((getFontStyle() & 0x10) != 0) {
graphics.setColor(Color.decode("#EEEEEE"));
graphics.fillRect(rX, rY, rW, rH);
}
graphics.setColor(getColor());
x = Utilities.drawTabbedText(segment, x, y, graphics, e, startOffset);
if ((getFontStyle() & 0x8) != 0) {
graphics.setColor(Color.RED);
graphics.drawRect(rX, rY, rW, rH);
}
return x;
}
@Override
public float getTabbedSpan(float x, TabExpander e) {
int offset = getStartOffset();
int endOffset = offset + getLength();
float tabX = e.nextTabStop(x, offset++);
firstTabWidth = tabX - x;
while (offset < endOffset) {
tabX = e.nextTabStop(tabX, offset++);
}
width = tabX - x;
return width;
}
/**
* Paints the specified line onto the graphics context. Note that this method munges the offset
* and count values of the segment.
*
* @param line
* The line segment
* @param tokens
* The token list for the line
* @param styles
* The syntax style list
* @param expander
* The tab expander used to determine tab stops. May be null
* @param gfx
* The graphics context
* @param x
* The x co-ordinate
* @param y
* The y co-ordinate
* @return The x co-ordinate, plus the width of the painted string
*/
public static int paintSyntaxLine(Segment line, Token tokens, SyntaxStyle[] styles, TabExpander expander, Graphics gfx,
int x, int y) {
Font defaultFont = gfx.getFont();
Color defaultColor = gfx.getColor();
for (;;) {
byte id = tokens.id;
if (id == Token.END) {
break;
}
int length = tokens.length;
if (id == Token.NULL) {
if (!defaultColor.equals(gfx.getColor())) {
gfx.setColor(defaultColor);
}
if (!defaultFont.equals(gfx.getFont())) {
gfx.setFont(defaultFont);
}
} else {
styles[id].setGraphicsFlags(gfx, defaultFont);
}
line.count = length;
x = Utilities.drawTabbedText(line, x, y, gfx, expander, 0);
line.offset += length;
tokens = tokens.next;
}
return x;
}
public static int getTabbedTextWidth(Graphics g,Segment segment,int x,TabExpander e, int startOffset){
List<Segment> segments=new ArrayList<Segment>();
List<Boolean> unis=new ArrayList<Boolean>();
getSegments(g.getFont(), segment, segments, unis);
Font origFont=g.getFont();
Font uniFont = defaultUniFont.deriveFont(origFont.getStyle(),origFont.getSize2D());
int ret=0;
int pos=0;
for(int i=0;i<segments.size();i++){
Segment seg=segments.get(i);
ret += Utilities.getTabbedTextWidth(seg, g.getFontMetrics(unis.get(i)?uniFont:origFont), 0, e, startOffset+pos);
pos += seg.length();
}
return ret;
}
/**
* Provides a mapping from the view coordinate space to the logical
* coordinate space of the model.
*
* @param v the view containing the view coordinates
* @param x the X coordinate
* @param y the Y coordinate
* @param a the allocated region to render into
* @param biasReturn always returns <code>Position.Bias.Forward</code>
* as the zero-th element of this array
* @return the location within the model that best represents the
* given point in the view
* @see View#viewToModel
*/
@Override
public int viewToModel(GlyphView v, float x, float y, Shape a,
Position.Bias[] biasReturn) {
int ret;
try {
if (a != null) {
sync(v);
Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : a.getBounds();
int p0 = v.getStartOffset();
int p1 = v.getEndOffset();
TabExpander expander = v.getTabExpander();
String docText = v.getDocument().getText(p0, p1-p0);
int offs = getTabbedTextOffset(v, docText, alloc.x, (int) x, expander, p0, true, null);
int retValue = p0 + offs;
if(retValue == p1) {
// No need to return backward bias as GlyphPainter1 is used for
// ltr text only.
retValue--;
}
biasReturn[0] = Position.Bias.Forward;
ret = retValue;
} else {
ret = -1;
}
} catch (BadLocationException e) {
//e.printStackTrace();
ret = -1;
IOHandler.writeErrorLog(e, "EXTERNAL CODE");
}
return ret;
}
public TabExpander getTabExpander() {
return tabExpander;
}
public static int getTabbedTextWidth(Segment segment,FontMetrics f,int x,TabExpander e, int startOffset){
Graphics g=new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB).getGraphics();
g.setFont(f.getFont());
return getTabbedTextWidth(g,segment,x,e,startOffset);
}
/**
* Paints the glyphs representing the given range.
*/
@Override
public void paint(GlyphView v, Graphics g, Shape a, int p0, int p1) {
try {
sync(v);
if (a != null ) {
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
String localText;
TabExpander expander = v.getTabExpander();
Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : a.getBounds();
// determine the x coordinate to render the glyphs
int x = alloc.x;
int p = v.getStartOffset();
if (p != p0) {
localText = v.getDocument().getText(p, p0-p);
float width = getTabbedTextWidth(v, localText, x, expander, p, null);
x += width;
}
// determine the y coordinate to render the glyphs
int y = alloc.y + Math.round(lm.getHeight() - lm.getDescent());
// render the glyphs
localText = v.getDocument().getText(p0, p1-p0);
g.setFont(font);
if( p0 > v.getStartOffset() || p1 < v.getEndOffset() ) {
Shape s = v.modelToView(p0, Position.Bias.Forward,
p1, Position.Bias.Backward, a);
Shape savedClip = g.getClip();
((Graphics2D)g).clip(s);
x=v.modelToView(v.getStartOffset(), a, Position.Bias.Forward).getBounds().x;
drawTabbedText(v, localText, x, y, g, expander,p0, null);
g.setClip(savedClip);
}
else {
drawTabbedText(v, localText, x, y, g, expander,p0, null);
}
}
} catch (BadLocationException e) {
//e.printStackTrace();
IOHandler.writeErrorLog(e, "EXTERNAL CODE");
}
}
float getTabbedTextWidth(View view, String txtStr, float x,
TabExpander e, int startOffset,
int[] justificationData) {
float nextX = x;
char[] txt = txtStr.toCharArray();
int txtOffset = 0;
int n = txtStr.length();
int charCount = 0;
int spaceAddon = 0;
int spaceAddonLeftoverEnd = -1;
int startJustifiableContent = 0;
int endJustifiableContent = 0;
if (justificationData != null) {
int offset = - startOffset + txtOffset;
View parent;
if (view != null && (parent = view.getParent()) != null) {
offset += parent.getStartOffset();
}
spaceAddon =justificationData[0];
spaceAddonLeftoverEnd =justificationData[1] + offset;
startJustifiableContent =justificationData[2] + offset;
endJustifiableContent =justificationData[3] + offset;
}
for (int i = txtOffset; i < n; i++) {
if (txt[i] == '\t'
|| ((spaceAddon != 0 || i <= spaceAddonLeftoverEnd)
&& (txt[i] == ' ')
&& startJustifiableContent <= i
&& i <= endJustifiableContent
)) {
// doesn't account for complex glyphs/constructed diacratics in windows. Skipping diacratic mark is an approximate solution.
if (glyphVector.getNumGlyphs() >= i) {
nextX += (glyphVector.getGlyphPosition(i).getX() - glyphVector.getGlyphPosition(i-charCount).getX());
}
charCount = 0;
if (txt[i] == '\t') {
if (e != null) {
nextX = e.nextTabStop(nextX, startOffset + i - txtOffset);
} else {
if (spaceVector.getNumGlyphs() >= 1) {
nextX += (spaceVector.getGlyphPosition(1).getX());
}
}
} else if (txt[i] == ' ') {
if (spaceVector.getNumGlyphs() >= 1) {
nextX += (spaceVector.getGlyphPosition(1).getX()) + spaceAddon;
}
if (i <= spaceAddonLeftoverEnd) {
nextX++;
}
}
} else if(txt[i] == '\n') {
// doesn't account for complex glyphs/constructed diacratics in windows. Skipping diacratic mark is an approximate solution.
if (glyphVector.getNumGlyphs() >= i) {
// Ignore newlines, they take up space and we shouldn't be counting them.
nextX += (glyphVector.getGlyphPosition(i).getX() - glyphVector.getGlyphPosition(i-charCount).getX());
}
charCount = 0;
} else {
charCount++;
}
}
// doesn't account for complex glyphs/constructed diacratics in windows. Skipping diacratic mark is an approximate solution.
if (glyphVector.getNumGlyphs() >= n) {
nextX += (glyphVector.getGlyphPosition(n).getX() - glyphVector.getGlyphPosition(n - charCount).getX());
}
return nextX - x;
}
int getTabbedTextOffset(View view,
String s,
int x0, int x, TabExpander e,
int startOffset,
boolean round,
int[] justificationData) {
if (x0 >= x) {
// x before x0, return.
return 0;
}
float currX = x0;
float nextX = currX;
// s may be a shared String, so it is copied prior to calling
// the tab expander
char[] txt = s.toCharArray();
int txtOffset = 0;
int txtCount = s.length();
int spaceAddon = 0 ;
int spaceAddonLeftoverEnd = -1;
int startJustifiableContent = 0 ;
int endJustifiableContent = 0;
if (justificationData != null) {
int offset = - startOffset + txtOffset;
View parent;
if (view != null && (parent = view.getParent()) != null) {
offset += parent.getStartOffset();
}
spaceAddon =justificationData[0];
spaceAddonLeftoverEnd =justificationData[1] + offset;
startJustifiableContent =justificationData[2] + offset;
endJustifiableContent =justificationData[3] + offset;
}
int n = s.length();
for (int i = 0; i < n; i++) {
if (txt[i] == '\t'
|| ((spaceAddon != 0 || i <= spaceAddonLeftoverEnd)
&& (txt[i] == ' ')
&& startJustifiableContent <= i
&& i <= endJustifiableContent
)){
if (txt[i] == '\t') {
if (e != null) {
nextX = (int) e.nextTabStop(nextX,
startOffset + i - txtOffset);
} else {
nextX += (spaceVector.getGlyphPosition(1).getX());
}
} else if (txt[i] == ' ') {
nextX += (spaceVector.getGlyphPosition(1).getX())+spaceAddon;
if (i <= spaceAddonLeftoverEnd) {
nextX++;
}
}
} else {
// doesn't account for complex glyphs/constructed diacratics in windows. Skipping diacratic mark is an approximate solution.
if (glyphVector.getNumGlyphs() >= i + 1) {
nextX += (glyphVector.getGlyphPosition(i+1).getX() - glyphVector.getGlyphPosition(i).getX());
}
}
if ((x >= currX) && (x < nextX)) {
// found the hit position... return the appropriate side
if (!round || (x - currX) < (nextX - x)) {
return i - txtOffset;
} else {
return i + 1 - txtOffset;
}
}
currX = nextX;
}
// didn't find, return end offset
return txtCount;
}
/**
* Draw the given Token. This will simply find the proper SyntaxStyle for
* the TokenType and then asks the proper Style to draw the text of the
* Token.
* @param segment
* @param x
* @param y
* @param graphics
* @param e
* @param token
* @return
*/
public int drawText(Segment segment, int x, int y,
Graphics graphics, TabExpander e, Token token) {
SyntaxStyle s = getStyle(token.type);
return s.drawText(segment, x, y, graphics, e, token.start);
}
/**
* Draw the given Token. This will simply find the proper SyntaxStyle for
* the TokenType and then asks the proper Style to draw the text of the
* Token.
* @param segment
* @param x
* @param y
* @param graphics
* @param e
* @param token
* @return
*/
public int drawText(Segment segment, int x, int y,
Graphics graphics, TabExpander e, Token token) {
SyntaxStyle s = getStyle(token.type);
return s.drawText(segment, x, y, graphics, e, token.start);
}
/**
* Draw the given Token. This will simply find the proper SyntaxStyle for
* the TokenType and then asks the proper Style to draw the text of the
* Token.
*
* @param segment
* @param x
* @param y
* @param graphics
* @param e
* @param token
* @return
*/
public int drawText(Segment segment, int x, int y,
Graphics graphics, TabExpander e, Token token) {
SyntaxStyle syntaxStyle = getStyle(token.type);
return syntaxStyle.drawText(segment, x, y, graphics, e, token.start);
}
public abstract float getSpan(View v, int p0, int p1, TabExpander e, float x);