使用 NSTextTable 在 NSTextView 中创建表格

问题描述 投票:0回答:1

我创建了一个基于 NSTextTableBlock 的表,并尝试向该表添加嵌套表。不幸的是它不起作用,有没有人有任何想法可以做到这一点。我在使用 HTML 之前尝试过同样的操作,但是在创建 CSS 表时,该样式仅适用于第一个属性。

@IBOutlet var textView: NSTextView!

override func viewDidLoad() {
    super.viewDidLoad()
        
    let table = getTableString()
    textView.textStorage?.setAttributedString(table)
}

func getTableString() -> NSMutableAttributedString {
    var table = NSTextTable()
    table.numberOfColumns = 4
    var mas = NSMutableAttributedString()

    // Header
    mas.append(createTableBlock(string: "Header. 1", textTable: table, row: 0, column: 0, width: 25, isHeader: true))
    mas.append(createTableBlock(string: "Header. 2", textTable: table, row: 0, column: 1, width: 25, isHeader: true))
    mas.append(createTableBlock(string: "Header. 3", textTable: table, row: 0, column: 2, width: 25, isHeader: true))
    mas.append(createTableBlock(string: "Header. 4", textTable: table, row: 0, column: 3, width: 25, isHeader: true))
    
    // Row 1
    mas.append(createTableBlock(string: "Nr. 1", textTable: table, row: 1, column: 0, width: 25))
    mas.append(createTableBlock(string: "Nr. 2", textTable: table, row: 1, column: 1, width: 25))
    mas.append(createTableBlock(string: "-mark-", textTable: table, row: 1, column: 2, width: 50))
    
    // Create the nested table
    var nestedTable = NSTextTable()
    nestedTable.numberOfColumns = 2
    var nestedMAS = NSMutableAttributedString()
    
    nestedMAS.append(createTableBlock(string: "Nested 1", textTable: nestedTable, row: 0, column: 0, width: 24, isNested: true))
    nestedMAS.append(createTableBlock(string: "Nested 2", textTable: nestedTable, row: 0, column: 1, width: 24, isNested: true))
    
    let needleRange = mas.string.range(of: "-mark-")!
    let insertionRange = NSRange(needleRange, in: mas.string)
    mas.replaceCharacters(in: insertionRange, with: nestedMAS)
    
    return mas
}

func createTableBlock(string: String, textTable: NSTextTable, row: Int, column: Int, width: CGFloat, isHeader: Bool = false, isNested: Bool = false) -> NSMutableAttributedString {
    var offset = 1
    if isHeader || isNested {
        offset = 1
    } else if column >= 2 {
        offset = 2
    }
    
    let block = NSTextTableBlock(table: textTable, startingRow: row, rowSpan: 1, startingColumn: column, columnSpan: offset)
    
    block.backgroundColor = isHeader ? .lightGray : .white
    block.setBorderColor(isNested ? .red : .green)
    block.setWidth(1.0, type: NSTextBlock.ValueType.absoluteValueType, for: NSTextBlock.Layer.border)
    block.setContentWidth(width, type: .percentageValueType)
    
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = isNested ? .center : .left
    paragraphStyle.textBlocks = [block]
    
    var mas = NSMutableAttributedString(string: string + "\n")
    mas.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, mas.length))
    
    return mas
}

我期望的应该是这样的:

但结果是这样的:

更新问题: 我能够将字符串插入到单元格中(感谢@Willeke),但不幸的是我无法将其作为双单元格插入。

@IBOutlet var textView: NSTextView!


override func viewDidLoad() {
    super.viewDidLoad()

    let table = getTableString()!
    textView.textStorage?.setAttributedString(table)
}

func getTableString() -> NSMutableAttributedString? {
    let table = NSTextTable()
    table.numberOfColumns = 4
    let mas: NSMutableAttributedString = NSMutableAttributedString()

    // Header
    mas.append(addCell(string: "Header. 1\n", textTable: table, row: 0, column: 0, width: 25, isHeader: true))
    mas.append(addCell(string: "Header. 2\n", textTable: table, row: 0, column: 1, width: 25, isHeader: true))
    mas.append(addCell(string: "Header. 3\n", textTable: table, row: 0, column: 2, width: 25, isHeader: true))
    mas.append(addCell(string: "Header. 4\n", textTable: table, row: 0, column: 3, width: 25, isHeader: true))
    
    // Row 1
    mas.append(addCell(string: "Nr. 1\n", textTable: table, row: 1, column: 0, width: 25))
    mas.append(addCell(string: "Nr. 2\n", textTable: table, row: 1, column: 1, width: 25))
    
    // Composed nested table
    mas.append(addNestedCell(textTable: table, row: 1, column: 2, width: 50))

    return mas
}

// Regular cell
func addCell(string:String, textTable: NSTextTable, row:Int, column:Int, columnSpan:Int=1, width:CGFloat, isHeader:Bool=false, isNested:Bool=false) -> NSMutableAttributedString {
    let block = createTextTableBlock(table: textTable, row: row, column: column, columnSpan: columnSpan, width: width, isHeader: isHeader, isNested: isNested)
    
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = isNested ? .center : .left
    paragraphStyle.textBlocks = [block]
    
    let mas = NSMutableAttributedString(string: string)
    mas.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, mas.length))
    
    return mas
}

// Nested cell
func addNestedCell(textTable: NSTextTable, row: Int, column: Int, width: CGFloat) -> NSMutableAttributedString {
    let parentBlock = createTextTableBlock(table: textTable, row: row, column: column, columnSpan: 2, width: width)
    
    // Create the nested table
    let nestedTable = NSTextTable()
    nestedTable.numberOfColumns = 2
    
    let nestedMAS = NSMutableAttributedString()
    
    // Nested cell 1
    nestedMAS.append(addCell(string: "Nested 1\n", textTable: nestedTable, row: 0, column: 0, width: 25, isNested: true))
    
    // Nested cell 2
    nestedMAS.append(addCell(string: "Nested 2\n", textTable: nestedTable, row: 0, column: 1, width: 25, isNested: true))
    
    let paraNestStyle = getParagraphStyle(nestedMAS)
    let textNestBlocks = paraNestStyle!.textBlocks

    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = .center
    paragraphStyle.textBlocks = [parentBlock]
    paragraphStyle.textBlocks.append(contentsOf: textNestBlocks)
    
    nestedMAS.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, nestedMAS.length))
    
    return nestedMAS
}

// TableBlock builder
func createTextTableBlock(table textTable:NSTextTable, row:Int, column:Int, columnSpan:Int=1, width:CGFloat, isHeader:Bool=false, isNested:Bool=false) -> NSTextTableBlock {
    let block = NSTextTableBlock(table: textTable, startingRow: row, rowSpan: 1, startingColumn: column, columnSpan: columnSpan)
    
    block.backgroundColor = isHeader ? .lightGray : .white
    block.setBorderColor(isNested ? .red : .green)
    block.setWidth(1.0, type: NSTextBlock.ValueType.absoluteValueType, for: NSTextBlock.Layer.border)
    block.setContentWidth(width, type: .percentageValueType)
    
    return block
}

// Get paragraph style from NSMutableAttributedString
func getParagraphStyle(_ attributedString:NSMutableAttributedString, at index:Int=0) -> NSMutableParagraphStyle? {
    let range = NSMakeRange(0, attributedString.length)
    guard let paraStyle = attributedString.attribute(NSAttributedString.Key.paragraphStyle, at:index, longestEffectiveRange:nil, in:range) as? NSMutableParagraphStyle else { return nil }
    return paraStyle
}

现在看起来像这样

swift macos nsmutableattributedstring nsmutableparagraphstyle
1个回答
0
投票

嵌套单元格位于两个表中,并且

paragraphStyle.textBlocks
必须包含每个表中单元格的
NSTextTableBlock

示例:

func getTableString() -> NSMutableAttributedString {
    let table = NSTextTable()
    table.numberOfColumns = 4
    let mas = NSMutableAttributedString()

    // Header
    mas.append(createTableCell(string: "Header. 1", textTable: table, row: 0, column: 0, width: 25, isHeader: true))
    mas.append(createTableCell(string: "Header. 2", textTable: table, row: 0, column: 1, width: 25, isHeader: true))
    mas.append(createTableCell(string: "Header. 3", textTable: table, row: 0, column: 2, width: 25, isHeader: true))
    mas.append(createTableCell(string: "Header. 4", textTable: table, row: 0, column: 3, width: 25, isHeader: true))
    
    // Row 1
    mas.append(createTableCell(string: "Nr. 1", textTable: table, row: 1, column: 0, width: 25))
    mas.append(createTableCell(string: "Nr. 2", textTable: table, row: 1, column: 1, width: 25))
    
    // Create the nested table
    let parentBlock = createTextTableBlock(textTable: table, row: 1, column: 2, columnSpan: 2, width: 50)
    let nestedTable = NSTextTable()
    nestedTable.numberOfColumns = 2
    mas.append(createTableCell(string: "Nested 1", textTable: nestedTable, row: 0, column: 0, width: 50, isNested: true, parentBlocks: [parentBlock]))
    mas.append(createTableCell(string: "Nested 2", textTable: nestedTable, row: 0, column: 1, width: 50, isNested: true, parentBlocks: [parentBlock]))
    
    return mas
}

func createTextTableBlock(textTable: NSTextTable, row: Int, column: Int, columnSpan: Int = 1, width: CGFloat, isHeader: Bool = false, isNested: Bool = false) -> NSTextTableBlock {
    let block = NSTextTableBlock(table: textTable, startingRow: row, rowSpan: 1, startingColumn: column, columnSpan: columnSpan)
    block.backgroundColor = isHeader ? .lightGray : .white
    block.setBorderColor(isNested ? .red : .green)
    block.setWidth(1.0, type: NSTextBlock.ValueType.absoluteValueType, for: NSTextBlock.Layer.border)
    block.setContentWidth(width, type: .percentageValueType)
    return block
}

func createTableCell(string: String, textTable: NSTextTable, row: Int, column: Int, columnSpan:Int=1, width: CGFloat, isHeader: Bool = false, isNested: Bool = false, parentBlocks: [NSTextTableBlock] = []) -> NSAttributedString {
    let block = createTextTableBlock(textTable: textTable, row: row, column: column, columnSpan: columnSpan, width: width, isHeader: isHeader, isNested: isNested)
    
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = isNested ? .center : .left
    paragraphStyle.textBlocks = parentBlocks + [block]

    return NSAttributedString(string: string + "\n", attributes: [.paragraphStyle: paragraphStyle])
}

结果:

© www.soinside.com 2019 - 2024. All rights reserved.