简体   繁体   中英

How to use rubyXL to lock existing cells but leave all empty cells unlocked?

How do I use rubyXL to lock the existing cells in a worksheet but leave all empty cells unlocked? (I don't want to make the user jump through any hoops like requiring him or her to create a new column before entering new data.)

I figured out how to lock existing cells using the technique presented in this StackOverflow post: How can we protect some parts of a sheet using rubyXL? (The basic idea is to (1) Create a new xf, (2) register the new xf with the workbook, (3) set the style_index of all existing cells to use this xf, then (4) set the WorksheetProtection for the sheet.)

However, when I do this and open the workbook in Excel, all the empty cells in the worksheet are also locked.

In principle, I need to add an "unlocked" xf to all unused cells; however, since these cells don't exist yet, there is no Cell object to which to set the "unlocked" xf.

There is a way to do this in Excel:

  1. Click the upper-left corner of the worksheet to select all cells.
  2. Go to "Format" -> "Format Cells", select the "protection" tab, and uncheck the "locked" box.
  3. Select the existing, occupied cells, got to "Format" -> "Format Cells", select the "protection" tab, and check the "locked" box.
  4. Go to "Tools" -> "Protection" -> "protect sheet" and protect the worksheet.

When I follows these steps then examine the worksheet using rubyXL, I see that there are three XL objects:

  1. The default XL object
  2. An XL object with protection enabled
  3. An XL object with protection specifically disabled.

The existing cells all use style/XL 2. So, I'm thinking that there must be a way to specify that all unused cells in the worksheet default to style/XL 3; but, I don't see how to specify this using rubyXL.

Any ideas?

I figured it out:

require "rubyXL"
require "rubyXL/convenience_methods"

workbook = RubyXL::Workbook.new
sheet = workbook.worksheets.first

# Crate an xf that locks the cell
locked_xf = workbook.cell_xfs.first.dup
locked_xf.protection = RubyXL::Protection.new(
  locked: true,
  hidden: false,
)
locked_id = workbook.register_new_xf(locked_xf)

# Crate an xf that does not lock the cell
unlocked_xf = workbook.cell_xfs.first.dup
unlocked_xf.protection = RubyXL::Protection.new(
  locked: false,
  hidden: false,
)
unlocked_id = workbook.register_new_xf(unlocked_xf)

# Create new cells.  Lock each one.
(0..5).each do |row|
  (0..5).each do |col|
    cell = sheet.add_cell(row, col, (row * col).to_s)
    cell.style_index = locked_id
  end
end

# Create a cell range to cover "all" rows. (Upper bound set at 16384)
range = RubyXL::ColumnRange.new
range.min = 1
range.max = 16384
range.width = 10.83203125  # be sure to set this, otherwise columns aren't visible.
range.style_index = unlocked_id
sheet.cols << range


# Lock the sheet
sheet.sheet_protection = RubyXL::WorksheetProtection.new(
  sheet:          true,
  objects:        true,
  scenarios:      true,
  format_cells:   true,
  format_columns: true,
  insert_columns: true,
  delete_columns: true,
  insert_rows:    true,
  delete_rows:    true
)

workbook.write("lock_test.xlsx")

(I also put a copy of this code here: https://github.com/kurmasz/rubyXL-recipes )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM