Estoy escribiendo un editor de texto para Mac OS X. Necesito mostrar caracteres ocultos en un NSTextView (como espacios, pestañas y caracteres especiales). He pasado mucho tiempo buscando cómo hacer esto, pero hasta ahora no he encontrado una respuesta. Si alguien pudiera señalarme en la dirección correcta, estaría agradecido.Mostrar caracteres ocultos en NSTextView
Respuesta
Eche un vistazo a la clase NSLayoutManager. Su NSTextView tendrá un administrador de diseño asociado, y el administrador de diseño es responsable de asociar un carácter (espacio, pestaña, etc.) con un glifo (la imagen de ese personaje dibujada en la pantalla).
En su caso, probablemente le interese más el método replaceGlyphAtIndex:withGlyph:
, que le permitiría reemplazar glifos individuales.
Lo que he hecho es anular el siguiente método en una subclase NSLayoutManager.
- (void)drawGlyphsForGlyphRange:(NSRange)range atPoint:(NSPoint)origin
{
[super drawGlyphsForGlyphRange:range atPoint:origin];
for (int i = range.location; i != range.location + range.length; i++)
{
// test each character in this range
// if appropriate replace it with -replaceGlyphAtIndex:withGlyph:
}
}
Me desplazo por el índice de cada carácter. El problema que ahora tengo es cómo determinar qué personaje se encuentra en cada ubicación. ¿Debo usar un método NSLayoutManager o preguntar a NSTextView? ¿Los índices en el primero son los mismos que en el segundo?
Puedo obtener un glifo individual con -glyphAtIndex: pero no puedo averiguar cómo determinar a qué personaje corresponde.
Obtiene el punto de código del personaje de esta manera: NSString * completeString = [[self textStorage] string]; NSUInteger characterIndex = [self characterIndexForGlyphAtIndex: index]; unichar characterToCheck = [completeString characterAtIndex: characterIndex]; – JanX2
Resolví el problema de convertir entre NSGlyphs y el unichar correspondiente en NSTextView. El código siguiente funciona muy bien y reemplaza espacios con las balas para texto visible:
- (void)drawGlyphsForGlyphRange:(NSRange)range atPoint:(NSPoint)origin
{
NSFont *font = [[CURRENT_TEXT_VIEW typingAttributes]
objectForKey:NSFontAttributeName];
NSGlyph bullet = [font glyphWithName:@"bullet"];
for (int i = range.location; i != range.location + range.length; i++)
{
unsigned charIndex = [self characterIndexForGlyphAtIndex:i];
unichar c =[[[self textStorage] string] characterAtIndex:charIndex];
if (c == ' ')
[self replaceGlyphAtIndex:charIndex withGlyph:bullet];
}
[super drawGlyphsForGlyphRange:range atPoint:origin];
}
Quizás - [setShowsControlCharacters NSLayoutManager:] y/o [- setShowsInvisibleCharacters NSLayoutManager:] va a hacer lo que quiera.
Escribí un editor de texto hace unos años - aquí hay un código sin sentido que debería hacer que mires (con suerte) la dirección correcta (esta es una subclase de NSLayoutManager por cierto) y sí sé que está goteando como el proverbial fregadero de la cocina) :
- (void)drawGlyphsForGlyphRange:(NSRange)glyphRange atPoint:(NSPoint)containerOrigin
{
if ([[[[MJDocumentController sharedDocumentController] currentDocument] editor] showInvisibles])
{
//init glyphs
unichar crlf = 0x00B6;
NSString *CRLF = [[NSString alloc] initWithCharacters:&crlf length:1];
unichar space = 0x00B7;
NSString *SPACE = [[NSString alloc] initWithCharacters:&space length:1];
unichar tab = 0x2192;
NSString *TAB = [[NSString alloc] initWithCharacters:&tab length:1];
NSString *docContents = [[self textStorage] string];
NSString *glyph;
NSPoint glyphPoint;
NSRect glyphRect;
NSDictionary *attr = [[NSDictionary alloc] initWithObjectsAndKeys:[NSUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@"invisiblesColor"]], NSForegroundColorAttributeName, nil];
//loop thru current range, drawing glyphs
int i;
for (i = glyphRange.location; i < NSMaxRange(glyphRange); i++)
{
glyph = @"";
//look for special chars
switch ([docContents characterAtIndex:i])
{
//space
case ' ':
glyph = SPACE;
break;
//tab
case '\t':
glyph = TAB;
break;
//eol
case 0x2028:
case 0x2029:
case '\n':
case '\r':
glyph = CRLF;
break;
//do nothing
default:
glyph = @"";
break;
}
//should we draw?
if ([glyph length])
{
glyphPoint = [self locationForGlyphAtIndex:i];
glyphRect = [self lineFragmentRectForGlyphAtIndex:i effectiveRange:NULL];
glyphPoint.x += glyphRect.origin.x;
glyphPoint.y = glyphRect.origin.y;
[glyph drawAtPoint:glyphPoint withAttributes:attr];
}
}
}
[super drawGlyphsForGlyphRange:glyphRange atPoint:containerOrigin];
}
Aquí hay una aplicación totalmente funcional y limpia
@interface GILayoutManager : NSLayoutManager
@end
@implementation GILayoutManager
- (void)drawGlyphsForGlyphRange:(NSRange)range atPoint:(NSPoint)point {
NSTextStorage* storage = self.textStorage;
NSString* string = storage.string;
for (NSUInteger glyphIndex = range.location; glyphIndex < range.location + range.length; glyphIndex++) {
NSUInteger characterIndex = [self characterIndexForGlyphAtIndex: glyphIndex];
switch ([string characterAtIndex:characterIndex]) {
case ' ': {
NSFont* font = [storage attribute:NSFontAttributeName atIndex:characterIndex effectiveRange:NULL];
[self replaceGlyphAtIndex:glyphIndex withGlyph:[font glyphWithName:@"periodcentered"]];
break;
}
case '\n': {
NSFont* font = [storage attribute:NSFontAttributeName atIndex:characterIndex effectiveRange:NULL];
[self replaceGlyphAtIndex:glyphIndex withGlyph:[font glyphWithName:@"carriagereturn"]];
break;
}
}
}
[super drawGlyphsForGlyphRange:range atPoint:point];
}
@end
de instalar, usar:
[myTextView.textContainer replaceLayoutManager:[[GILayoutManager alloc] init]];
para conocer los nombres de glifo de la fuente, usted tiene que ir a CoreGraphics:
CGFontRef font = CGFontCreateWithFontName(CFSTR("Menlo-Regular"));
for (size_t i = 0; i < CGFontGetNumberOfGlyphs(font); ++i) {
printf("%s\n", [CFBridgingRelease(CGFontCopyGlyphNameForGlyph(font, i)) UTF8String]);
}
Muchas gracias por compartir esto. – uchuugaka
Publicaré adiciones más adelante para la función de reemplazo de la función en desuso, así como un cambio para evitar problemas con el diseño contiguo. – uchuugaka
Yo agregaría que es mejor ir hoy a Texto principal para la información del nombre de la fuente. CTFont y amigos están mucho mejor. – uchuugaka
Aquí está la solución de Pol en Swift:
class MyLayoutManager: NSLayoutManager {
override func drawGlyphsForGlyphRange(glyphsToShow: NSRange, atPoint origin: NSPoint) {
if let storage = self.textStorage {
let s = storage.string
let startIndex = s.startIndex
for var glyphIndex = glyphsToShow.location; glyphIndex < glyphsToShow.location + glyphsToShow.length; glyphIndex++ {
let characterIndex = self.characterIndexForGlyphAtIndex(glyphIndex)
let ch = s[startIndex.advancedBy(characterIndex)]
switch ch {
case " ":
let attrs = storage.attributesAtIndex(characterIndex, effectiveRange: nil)
if let font = attrs[NSFontAttributeName] {
let g = font.glyphWithName("periodcentered")
self.replaceGlyphAtIndex(glyphIndex, withGlyph: g)
}
case "\n":
let attrs = storage.attributesAtIndex(characterIndex, effectiveRange: nil)
if let font = attrs[NSFontAttributeName] {
// let g = font.glyphWithName("carriagereturn")
let g = font.glyphWithName("paragraph")
self.replaceGlyphAtIndex(glyphIndex, withGlyph: g)
}
case "\t":
let attrs = storage.attributesAtIndex(characterIndex, effectiveRange: nil)
if let font = attrs[NSFontAttributeName] {
let g = font.glyphWithName("arrowdblright")
self.replaceGlyphAtIndex(glyphIndex, withGlyph: g)
}
default:
break
}
}
}
super.drawGlyphsForGlyphRange(glyphsToShow, atPoint: origin)
}
}
y para indicar los nombres de glifo:
func listFonts() {
let font = CGFontCreateWithFontName("Menlo-Regular")
for var i:UInt16 = 0; i < UInt16(CGFontGetNumberOfGlyphs(font)); i++ {
if let name = CGFontCopyGlyphNameForGlyph(font, i) {
print("name: \(name) at index \(i)")
}
}
}
- 1. ¿Cómo mostrar divs ocultos en mouseover?
- 2. Cómo mostrar los caracteres ocultos por defecto (ZERO WIDTH SPACE es decir & # 8203)
- 3. NSTextField o NSTextView?
- 4. Mostrar caracteres ASCII extendidos
- 5. Finalización en NSTextView
- 6. Enfoque en un NSTextView
- 7. Campos ocultos en AngularJs
- 8. Eclipse: He activado caracteres ocultos ahora no puedo desactivar
- 9. ¿Bloc de notas ++ muestra todos los caracteres ocultos?
- 10. NSpoint desde el punto de inserción NSTextView
- 11. Cómo mantener SEO mientras utilizo JQuery para mostrar divs ocultos
- 12. Mostrar caracteres especiales usando System.out.println
- 13. ¿Cómo mostrar caracteres especiales en Android?
- 14. Cómo mostrar caracteres japoneses en JTextArea
- 15. Mostrar caracteres Unicode en TextView Android
- 16. Mostrar caracteres UTF-8 en la consola
- 17. UILabel/NSTextView vs. CATextLayer
- 18. NSTextView resaltado de sintaxis
- 19. configurando un NSTextView
- 20. Valor de NSTextView cambiado
- 21. Bordes ocultos en Graphviz
- 22. Cómo retransmitir contenido de NSTextView para que mis caracteres de tabulación se dibujen con un ancho de 4 caracteres
- 23. Localización .NET: caracteres japoneses Mostrar como cuadrados
- 24. No mostrar^M caracteres con emacs
- 25. Mostrar caracteres en espacios en blanco en gvim
- 26. Google SEO y elementos ocultos
- 27. ¿Cómo configurar la fuente en NSTextView?
- 28. Configuración de fuentes predeterminadas en NSTextView
- 29. Desplazamiento NSTextView línea por línea
- 30. Cómo detectar caracteres ocultos en cadena (por ejemplo, espacio de ancho cero) durante la depuración
@ Pol publicó la información más completa sobre una clase difícil de trabajar debido a los escasos documentos. Pero ambos tienen una limitación en el sentido de que este método está en desuso y el método más nuevo parece ser un poco más difícil en el sentido de que usa matrices en C: D Agregaré algunos ejemplos basados en eso. – uchuugaka