HotXLS menyimpan selection worksheet dan posisi scroll per pane lewat satu API yang sadar pane di TXLSWorksheet maupun TXLSXWorksheet: SelectAreas, GetSelectedAreas, ScrollWindow, dan TryGetWindowScroll. Untuk berkas .xls klasik, HotXLS menulis record Selection BIFF8 (0x001D) yang masing-masing menampung paling banyak 1369 area, mengonversi nama pane logis ke byte pane yang didefinisikan format, dan menaruh tiap sumbu scroll di record Window2 atau Pane tempat Excel mengharapkannya
Masalahnya biasanya muncul di tool rekonsiliasi atau audit. Tool itu membuka export buku besar, mencari setiap sel yang tidak cocok dengan sistem sumber, dan menyimpan workbook dengan sel-sel itu sudah terpilih di bawah baris header yang dibekukan, sehingga reviewer mendarat langsung di selisihnya alih-alih menggulung mencarinya. Dengan empat puluh selisih semuanya lancar. Berkas akhir bulan memuat 3,000, dan satu record Selection yang menampung 3,000 area tidak mungkin ada: body-nya butuh 18,009 byte, lebih dari dua kali lipat kapasitas satu record BIFF8. Posisi scroll punya jebakan serupa. Di sheet dengan frozen panes, "di mana pengguna sedang melihat" adalah empat pane yang berbagi dua posisi baris dan dua posisi kolom, bukan satu koordinat
Mengapa selection besar butuh lebih dari satu record Selection?
Selection besar butuh beberapa record karena body record BIFF8 dibatasi 8224 byte dan tiap area terpilih memakan enam byte tetap. [MS-XLS] §2.4.248 menyusun record Selection sebagai bagian tetap 9 byte (byte pane, rwAct dan colAct untuk sel aktif, irefAct untuk area aktif, dan cref untuk jumlah area) diikuti cref struktur RefU yang masing-masing menampung dua baris 16-bit dan dua kolom 8-bit. Hitungan terbesar yang muat adalah (8224 − 9) / 6 dibulatkan ke bawah, yaitu 1369, dan itu menghasilkan body 8223 byte, satu byte di bawah batas. TXLSWorksheet.StoreSelectionGroup memakai konstanta itu sebagai MaxAreasPerRecord dan menulis group yang lebih besar sebagai record Selection berurutan untuk pane yang sama, 1369 area sekali jalan
Detail yang menggigit adalah irefAct. Tiap chunk mengulang baris aktif, kolom aktif, dan indeks area aktif yang sama, dan irefAct mengindeks urutan agregat semua chunk, bukan area di dalam record yang membawanya. Selection yang melewati batas satu area membuat ini konkret: 1370 area dengan area terakhir aktif menjadi dua record, yang pertama dengan cref 1369 dan yang kedua dengan cref 1, dan keduanya membawa irefAct 1369. Nilai itu lebih besar daripada jumlah area milik record kedua sendiri. Reader yang memeriksa irefAct terhadap cref di tiap record akan menolak berkas yang valid, dan reader yang mengganti state-nya di tiap record akan menjatuhkan 1369 area pertama. Reader HotXLS menambahkan record se-pane yang berurutan ke satu group, mensyaratkan semua chunk sepakat soal sel aktif dan indeksnya, dan menjalankan range check hanya di record EOF milik worksheet, setelah urutan penuh diketahui. Overload SelectAreas yang pane-first jadi tidak punya plafon 1369 area. Ia memvalidasi setiap referensi A1 dan indeks aktif sebelum mengambil write lock worksheet, dan mengembalikan False dengan selection sebelumnya tak berubah bila ada yang cacat
var
Book: TXLSWorkbook;
Sheet: TXLSWorksheet;
Diffs: TXLSSelectedAreas;
I: Integer;
begin
Book := TXLSWorkbook.Create;
try
Sheet := Book.Sheets.Add;
Sheet.FreezePanes(1, 1); // baris header dan kolom A tetap di tempat
SetLength(Diffs, 3000);
for I := 0 to High(Diffs) do
Diffs[I] := Format('C%d', [I + 2]);
// Freeze mereset selection yang tersimpan, jadi pilih setelah freeze.
// 3000 area tersimpan sebagai tiga record Selection: 1369 + 1369 + 262
if not Sheet.SelectAreas(xlspBottomRight, Diffs, 0) then
raise Exception.Create('Selection rejected');
Book.SaveAs('reconciliation.xls');
finally
Book.Free;
end;
end;
Byte pane mana yang dipakai sebuah record Selection?
Record Selection mengenali pane-nya lewat kode numerik yang didefinisikan format: 0 untuk bottom-right, 1 untuk top-right, 2 untuk bottom-left, dan 3 untuk top-left. Enumerasi publik TXLSPanePosition dideklarasikan dalam urutan baca, xlspTopLeft, xlspTopRight, xlspBottomLeft, xlspBottomRight, sehingga Ord(xlspTopLeft) adalah 0, yang di dalam berkas berarti pane bottom-right. Type cast enum langsung ke byte pane akan menulis semua selection top-left ke pane bottom-right tanpa error apa pun. Setiap entry point HotXLS yang sadar pane mengonversi enum lewat statement case eksplisit, jadi caller tidak pernah berurusan dengan kode numerik sama sekali. Eksistensi pane juga diperiksa: pane top-right hanya ada dengan split vertikal, bottom-left hanya dengan split horizontal, dan bottom-right hanya dengan keduanya. Untuk pane yang tidak dimiliki geometri split atau freeze saat ini, SelectAreas mengembalikan False, dan GetSelectedAreas mengembalikan array kosong dengan ActiveAreaIndex diset -1, tanpa membuat pane, objek selection, atau sel apa pun di workbook
Di mana posisi scroll tiap pane berada?
Posisi scroll tiap pane terbagi ke dua record, karena empat pane hanya berbagi dua posisi baris dan dua posisi kolom. Di workbook klasik, baris pertama yang terlihat milik pane atas dan kolom pertama yang terlihat milik pane kiri adalah Window2.rwTop dan Window2.colLeft, sedangkan baris milik pane bawah dan kolom milik pane kanan adalah Pane.rwTop dan Pane.colLeft. Karena itu ScrollWindow(xlspTopRight, R, C) menulis Window2.rwTop dan Pane.colLeft, dan mengatur kolom pane top-right ikut memindahkan pane bottom-right, sama seperti keduanya berbagi satu scrollbar horizontal di Excel. Metode publik memakai nomor baris dan kolom berbasis 1. Pane yang tidak ada mengembalikan False dan menyetel kedua output query ke nol, dan koordinat di luar jangkauan ditolak sebelum salah satu sumbu berubah. Tidak ada bagian di sini yang bergantung pada cara viewer menggambar grid. Kontrol rendering menyimpan TopRow dan LeftCol-nya sendiri, seperti dijelaskan artikel soal merender workbook di grid VCL kustom, dan itu state runtime, bukan yang tersimpan
XLSX membentangkan data yang sama ke dua elemen: sheetView/@topLeftCell (ECMA-376 Part 1, §18.3.1.87) untuk jendela secara keseluruhan dan anak pane/@topLeftCell (§18.3.1.66) untuk sisi kanan bawah dari sebuah split. Kedua atribut bisa hadir sekaligus. HotXLS membaca atribut luar lebih dulu ke field level jendela, membiarkan anak pane meng-override hanya field level pane, dan menulis keduanya kembali secara terpisah. Mencampur dua lapisan itu menjadi satu adalah persis cara posisi scroll atas atau kiri menghilang diam-diam saat dimuat. Salinan worksheet membawa kedua lapisan di kedua engine. Entry point yang lebih lama mempertahankan perilaku aslinya: properti ScrollRow dan ScrollColumn klasik, serta SetPaneScroll dan GetPaneScroll XLSX yang berbasis nol. Geometri freeze dan split sendiri dikonfigurasi lewat setelan level sheet yang dibahas di proteksi sheet, page setup, dan printing
var
Row, Col: Integer;
begin
Sheet.FreezePanes(1, 1);
// Bottom-right: sumbu baris bawah (Pane.rwTop) dan sumbu kolom kanan (Pane.colLeft)
Sheet.ScrollWindow(xlspBottomRight, 500, 3);
// Top-right berbagi sumbu kolom kanan, jadi ini juga memindahkan bottom-right ke kolom 6
Sheet.ScrollWindow(xlspTopRight, 1, 6);
if Sheet.TryGetWindowScroll(xlspBottomRight, Row, Col) then
Memo1.Lines.Add(Format('Bottom-right starts at row %d, column %d', [Row, Col]));
// Bottom-right mulai di baris 500, kolom 6
end;
Apa yang terjadi saat record Selection korup?
Saat record Selection korup, HotXLS mempertahankannya sebagai byte opaque, melaporkan kode diagnostik 1304 (xlsDiagnosticSelectionRecordInvalid), dan menulis kembali body aslinya byte demi byte saat menyimpan. Sebelum sebuah record bergabung ke group pane-nya, reader memeriksanya berurutan. Byte pane harus 3 atau kurang. Record untuk satu pane harus kontigu di stream. Sembilan byte tetap harus ada. cref harus di antara 1 dan 1369, dan panjang body harus tepat 9 + cref × 6 byte. Semua chunk dalam satu group harus sepakat soal sel aktif dan irefAct, bit tanda irefAct tidak boleh terpasang, kolom aktif harus berada di grid, dan tidak boleh ada area dengan batas terbalik. Masalah di satu record fisik dilaporkan sekali per record. Kontradiksi yang baru muncul setelah agregasi, seperti irefAct yang menunjuk melampaui jumlah area total atau sel aktif di luar area yang diindeks, dilaporkan sekali per group di EOF. Group yang tidak valid tetap tak terlihat bagi API bertipe: GetSelectedAreas mengembalikan array kosong dengan indeks -1 untuk pane itu, sementara semua pane lain tetap bekerja
var
I: Integer;
D: TXLSDiagnostic;
begin
if Book.Open('supplier-upload.xls') <> 1 then
Exit;
for I := 0 to Book.Diagnostics.Count - 1 do
begin
D := Book.Diagnostics[I];
if D.Code = xlsDiagnosticSelectionRecordInvalid then
Log.Add(Format('%s: record $%.4x kept opaque (%s)',
[D.SheetName, D.RecordId, D.Message]));
end;
end;
Bagaimana selection bertahan dari insert baris dan kolom?
Selection bertahan dari suntingan struktural karena menyisipkan atau menghapus baris atau kolom utuh memetakan ulang setiap group pane yang terwakili di engine klasik maupun XLSX lewat satu remapper bersama. Area yang selamat menjaga urutannya dan area aktif menjaga identitasnya. Bila area aktif terhapus, penerus selamat pertama menjadi aktif, lalu pendahulu selamat terakhir bila tidak ada yang menyusulnya. Bila semua area terhapus, group menciut menjadi satu sel di batas penghapusan, dan sel aktif yang tak lagi jatuh di dalam area terpilih bergeser ke pojok kiri atas area itu, sehingga indeks dan koordinat tidak pernah saling bertentangan. Batas-batas ini disengaja. Group klasik yang tidak valid dilewati remapper alih-alih ditulis ulang jadi selection buatan, sehingga byte aslinya tetap round-trip. Menyunting satu pane hanya mengganti record pane itu dan membiarkan yang lain identik byte demi byte. ODS tidak mendapat state selection pane sama sekali, karena ODF tidak punya struktur view worksheet yang setara untuk membawanya
Kalau aplikasi Anda menulis berkas .xls yang dibuka dan dinavigasi pengguna — entah untuk meninjau sel yang ditandai, melanjutkan dari tempat mereka berhenti, atau membagikan dashboard beku — API selection dan scroll yang sadar pane adalah bagian dari komponen spreadsheet Delphi HotXLS, dan bekerja dengan cara yang sama untuk XLS maupun XLSX