Bagaimana menghindari penggunaan Select di Excel VBA

537

Saya telah mendengar banyak tentang kebencian yang dapat dimengerti tentang penggunaan .Selectdi Excel VBA, tetapi saya tidak yakin bagaimana cara menghindari menggunakannya. Saya menemukan bahwa kode saya akan lebih dapat digunakan kembali jika saya dapat menggunakan variabel daripada Selectfungsi. Namun, saya tidak yakin bagaimana merujuk pada hal-hal (seperti yang ActiveCelllain - lain) jika tidak menggunakan Select.

Saya telah menemukan artikel ini pada rentang dan contoh ini tentang manfaat tidak menggunakan pilih tetapi tidak dapat menemukan apa pun tentang caranya ?

BiGXERO
sumber
14
Penting untuk dicatat bahwa ada beberapa contoh ketika menggunakan Selectdan / atau ActiveSheetetc dll benar-benar tidak dapat dihindari. Berikut adalah contoh yang saya temukan: stackoverflow.com/questions/22796286/…
Rick mendukung Monica
9
Dan ada beberapa kesempatan - mengedit data grafik dalam ppt dengan file excel yang mendasarinya menjadi satu - di mana mengaktifkan atau memilih diperlukan.
brettdj
@ brettdj - inilah contoh terbaru . Untuk mengatur semua lembar di buku kerja ke nilai yang sama, tampaknya .Select / .Selectiondiperlukan.
BruceWayne
3
@bruce dari QA yang sama sepertinya tidak
chris neilsen

Jawaban:

565

Beberapa contoh cara menghindari pilih

Gunakan Dimvariabel d

Dim rng as Range

Setvariabel ke rentang yang diperlukan. Ada banyak cara untuk merujuk ke rentang sel tunggal

Set rng = Range("A1")
Set rng = Cells(1,1)
Set rng = Range("NamedRange")

atau rentang multi-sel

Set rng = Range("A1:B10")
Set rng = Range("A1", "B10")
Set rng = Range(Cells(1,1), Cells(10,2))
Set rng = Range("AnotherNamedRange")
Set rng = Range("A1").Resize(10,2)

Anda dapat menggunakan cara pintas ke Evaluatemetode, tetapi ini kurang efisien dan umumnya harus dihindari dalam kode produksi.

Set rng = [A1]
Set rng = [A1:B10]

Semua contoh di atas merujuk ke sel di lembar aktif . Kecuali Anda secara khusus ingin bekerja hanya dengan lembar aktif, lebih baik untuk Dim Worksheetvariabel juga

Dim ws As Worksheet
Set ws = Worksheets("Sheet1")
Set rng = ws.Cells(1,1)
With ws
    Set rng = .Range(.Cells(1,1), .Cells(2,10))
End With

Jika Anda tidak ingin bekerja dengan ActiveSheet, untuk kejelasan yang terbaik untuk menjadi eksplisit. Tetapi berhati-hatilah, karena beberapa Worksheetmetode mengubah lembar aktif.

Set rng = ActiveSheet.Range("A1")

Sekali lagi, ini merujuk pada buku kerja aktif . Kecuali jika Anda secara khusus ingin bekerja hanya dengan ActiveWorkbookatau ThisWorkbook, lebih baik untuk Dim Workbookvariabel juga.

Dim wb As Workbook
Set wb = Application.Workbooks("Book1")
Set rng = wb.Worksheets("Sheet1").Range("A1")

Jika Anda tidak ingin bekerja dengan ActiveWorkbook, untuk kejelasan yang terbaik untuk menjadi eksplisit. Tapi hati-hati, karena banyak WorkBookmetode mengubah buku aktif.

Set rng = ActiveWorkbook.Worksheets("Sheet1").Range("A1")

Anda juga dapat menggunakan ThisWorkbookobjek untuk merujuk ke buku yang berisi kode yang sedang berjalan.

Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A1")

Sepotong kode yang umum (buruk) adalah membuka buku, mendapatkan beberapa data lalu tutup kembali

Ini buruk:

Sub foo()
    Dim v as Variant
    Workbooks("Book1.xlsx").Sheets(1).Range("A1").Clear
    Workbooks.Open("C:\Path\To\SomeClosedBook.xlsx")
    v = ActiveWorkbook.Sheets(1).Range("A1").Value
    Workbooks("SomeAlreadyOpenBook.xlsx").Activate
    ActiveWorkbook.Sheets("SomeSheet").Range("A1").Value = v
    Workbooks(2).Activate
    ActiveWorkbook.Close()
End Sub

Dan akan lebih baik seperti:

Sub foo()
    Dim v as Variant
    Dim wb1 as Workbook
    Dim  wb2 as Workbook
    Set wb1 = Workbooks("SomeAlreadyOpenBook.xlsx")
    Set wb2 = Workbooks.Open("C:\Path\To\SomeClosedBook.xlsx")
    v = wb2.Sheets("SomeSheet").Range("A1").Value
    wb1.Sheets("SomeOtherSheet").Range("A1").Value = v
    wb2.Close()
End Sub

Pass rentang ke Subdan Functionsebagai variabel Range

Sub ClearRange(r as Range)
    r.ClearContents
    '....
End Sub

Sub MyMacro()
    Dim rng as Range
    Set rng = ThisWorkbook.Worksheets("SomeSheet").Range("A1:B10")
    ClearRange rng
End Sub

Anda juga harus menerapkan Metode (seperti Finddan Copy) ke variabel

Dim rng1 As Range
Dim rng2 As Range
Set rng1 = ThisWorkbook.Worksheets("SomeSheet").Range("A1:A10")
Set rng2 = ThisWorkbook.Worksheets("SomeSheet").Range("B1:B10")
rng1.Copy rng2

Jika Anda mengulangi rentang sel, seringkali lebih baik (lebih cepat) untuk menyalin nilai rentang ke array varian terlebih dahulu dan mengulanginya.

Dim dat As Variant
Dim rng As Range
Dim i As Long

Set rng = ThisWorkbook.Worksheets("SomeSheet").Range("A1:A10000")
dat = rng.Value  ' dat is now array (1 to 10000, 1 to 1)
for i = LBound(dat, 1) to UBound(dat, 1)
    dat(i,1) = dat(i,1) * 10 'or whatever operation you need to perform
next
rng.Value = dat ' put new values back on sheet

Ini adalah pengecap kecil untuk apa yang mungkin.

chris neilsen
sumber
7
menambah jawaban yang brilian ini bahwa untuk bekerja dengan rentang Anda tidak perlu tahu ukuran sebenarnya selama Anda tahu bagian kiri atas ... misalnya rng1(12, 12)akan bekerja meskipun rng1 ditetapkan [A1:A10]hanya.
MikeD
3
@ Chris Chrisneilsen, saya yakin Anda juga bisa menggunakan awalan lembar kerja sebelum notasi referensi sel steno untuk menyelamatkan Anda dari mengetik Rangeseperti ini: ActiveSheet.[a1:a4]atau ws.[b6].
Logan Reed
3
@AndrewWillems ... atau 48 kali dalam posting ini, tetapi siapa yang menghitung. ☺ ... tapi serius, ini mudah dilupakan ketika bekerja dengan variabel yang memegang objek. Sebuah variantvariabel tidak memerlukan Set sampai Anda menetapkan sebuah objek untuk itu. Misalnya, Dim x: x = 1boleh saja, tetapi Dim x: x = Sheets("Sheet1")akan menghasilkan Kesalahan 438. Namun hanya untuk membingungkan / mengklarifikasi tidakDim x: x = Range("A1") akan membuat kesalahan. Mengapa? ... karena itu menetapkan nilai objek ke variabel, bukan referensi ke objek itu sendiri (karena itu setara dengan )Dim x: x = Range("A1").Value
ashleedawg
1
@ user3932000 Saya tidak mengetahui skenario di mana nama sheet berubah secara otomatis. Adapun nama file, itu hanya akan melakukan itu jika sudah ada file dari nama itu di folder. Cukup gunakan Simpan ... atau kode nama file untuk menyimpannya di bawah sebagai string. Jika Anda tidak dapat menyelesaikan masalah ini, Anda harus mengajukan pertanyaan terpisah tentang itu alih-alih berkomentar.
TylerH
1
@ user3932000 yang akan membuat Q menarik. Saya yakin ada cara untuk menanganinya .. Anda sudah berada di SO cukup lama untuk mengetahui pembajakan utas komentar pada Q lama bukan cara untuk pergi
chris neilsen
212

Dua alasan utama mengapa .Select/ .Activate/ Selection/ Activecell/ Activesheet/ Activeworkbooketc ... harus dihindari

  1. Ini memperlambat kode Anda.
  2. Ini biasanya merupakan penyebab utama kesalahan runtime.

Bagaimana kita menghindarinya?

1) Langsung bekerja dengan objek yang relevan

Pertimbangkan kode ini

Sheets("Sheet1").Activate
Range("A1").Select
Selection.Value = "Blah"
Selection.NumberFormat = "@"

Kode ini juga dapat ditulis sebagai

With Sheets("Sheet1").Range("A1")
    .Value = "Blah"
    .NumberFormat = "@"
End With

2) Jika perlu mendeklarasikan variabel Anda. Kode yang sama di atas dapat ditulis sebagai

Dim ws as worksheet

Set ws = Sheets("Sheet1")

With ws.Range("A1")
    .Value = "Blah"
    .NumberFormat = "@"
End With
Siddharth Rout
sumber
17
Itu jawaban yang bagus, tetapi apa yang saya lewatkan tentang topik ini adalah ketika kita benar-benar membutuhkan Aktifkan. Semua orang mengatakan itu buruk, tetapi tidak ada yang menjelaskan kasus di mana masuk akal untuk menggunakannya. Misalnya saya bekerja dengan 2 buku kerja dan tidak bisa memulai makro di salah satu buku kerja tanpa mengaktifkannya terlebih dahulu. Bisakah Anda menguraikan sedikit mungkin? Juga jika misalnya saya tidak mengaktifkan lembar ketika menyalin rentang dari satu lembar ke lembar lainnya, ketika saya menjalankan program, sepertinya mengaktifkan masing-masing lembar, secara implisit.
user3032689
1
Saya menemukan bahwa Anda kadang-kadang perlu mengaktifkan sheet terlebih dahulu jika Anda perlu menempelkan atau memfilter data di dalamnya. Saya akan mengatakan yang terbaik untuk menghindari mengaktifkan sebanyak mungkin tetapi ada beberapa contoh di mana Anda perlu melakukannya. Jadi tetap aktifkan dan pilih seminimal mungkin sesuai jawaban di atas.
Nick
7
Saya pikir intinya bukan untuk sepenuhnya menghindari menggunakannya, tetapi hanya sebanyak mungkin. jika Anda ingin menyimpan buku kerja, sehingga ketika seseorang membukanya sel tertentu dalam lembaran tertentu dipilih, maka Anda harus memilih lembar dan sel itu. copy / paste adalah contoh yang buruk, setidaknya dalam hal nilai, itu bisa dilakukan lebih cepat dengan kode sepertiSheets(2).[C10:D12].Value = Sheets(1).[A1:B3].Value
robotik
1
@Nick Anda tidak perlu Mengaktifkan lembar untuk menempelkan atau menyaringnya. Gunakan objek lembar dalam perintah tempel atau filter. Menjadi lebih mudah saat Anda mempelajari model objek Excel melalui latihan. Saya percaya satu-satunya waktu saya menggunakan .Aktifkan adalah ketika saya membuat lembar baru, tapi saya ingin lembar asli muncul ketika kode selesai.
phrebh
3
@ phrebh Anda tidak perlu menggunakan .Activateuntuk pindah ke lembar asli, cukup gunakanApplication.Goto
GMalc
88

Satu titik kecil penekanan saya akan menambahkan ke semua jawaban luar biasa yang diberikan di atas:

Mungkin hal terbesar yang dapat Anda lakukan untuk menghindari penggunaan Select adalah sebanyak mungkin, gunakan rentang bernama (dikombinasikan dengan nama variabel yang bermakna) dalam kode VBA Anda . Poin ini disebutkan di atas, tetapi sedikit ditutup-tutupi; Namun, itu patut mendapat perhatian khusus.

Berikut adalah beberapa alasan tambahan untuk menggunakan rentang bernama secara liberal, namun saya yakin saya bisa memikirkan lebih banyak.

Rentang yang diberi nama membuat kode Anda lebih mudah dibaca dan dipahami.

Contoh:

Dim Months As Range
Dim MonthlySales As Range

Set Months = Range("Months")
'e.g, "Months" might be a named range referring to A1:A12

Set MonthlySales = Range("MonthlySales")
'e.g, "Monthly Sales" might be a named range referring to B1:B12

Dim Month As Range
For Each Month in Months
    Debug.Print MonthlySales(Month.Row)
Next Month

Cukup jelas apa yang disebut rentang Monthsdan MonthlySaleskandungannya, dan apa yang dilakukan prosedur ini.

Mengapa ini penting? Sebagian karena lebih mudah bagi orang lain untuk memahaminya, tetapi bahkan jika Anda adalah satu-satunya orang yang akan pernah melihat atau menggunakan kode Anda, Anda masih harus menggunakan rentang bernama dan nama variabel yang baik karena ANDA AKAN LUPA apa yang Anda maksud dengan itu setahun kemudian, dan Anda akan menghabiskan 30 menit hanya mencari tahu apa yang dilakukan kode Anda.

Rentang yang diberi nama memastikan bahwa makro Anda tidak rusak saat (tidak jika!) Konfigurasi spreadsheet berubah.

Pertimbangkan, jika contoh di atas telah ditulis seperti ini:

Dim rng1 As Range
Dim rng2 As Range

Set rng1 = Range("A1:A12")
Set rng2 = Range("B1:B12")

Dim rng3 As Range
For Each rng3 in rng1 
    Debug.Print rng2(rng3.Row)
Next rng3

Kode ini akan berfungsi dengan baik pada awalnya - yaitu sampai Anda atau pengguna yang akan datang memutuskan "gee wiz, saya pikir saya akan menambahkan kolom baru dengan tahun di Kolom A!", Atau meletakkan kolom pengeluaran antara bulan dan kolom penjualan, atau tambahkan tajuk ke setiap kolom. Sekarang, kode Anda rusak. Dan karena Anda menggunakan nama variabel yang mengerikan, Anda akan membutuhkan lebih banyak waktu untuk mencari tahu cara memperbaikinya daripada yang seharusnya.

Jika Anda menggunakan rentang bernama untuk memulai, kolom Monthsdan Salesdapat dipindahkan di sekitar yang Anda suka, dan kode Anda akan terus berfungsi dengan baik.

Rick mendukung Monica
sumber
6
Perdebatan tentang apakah rentang bernama adalah desain spreadsheet yang baik atau buruk terus berlanjut - Saya benar-benar di kamp tidak. Dalam pengalaman saya, mereka meningkatkan kesalahan (untuk pengguna standar yang tidak membutuhkan kode).
brettdj
12
Saya setuju dengan filosofi pengembangan Anda; namun saya pikir makalah ini tidak masuk akal. Ini berbicara tentang bagaimana nama rentang dapat membingungkan pemula yang men-debug spreadsheet, tetapi siapa pun yang menggunakan novis untuk melihat spreadsheet kompleks mendapatkan apa yang pantas mereka dapatkan! Saya dulu bekerja untuk sebuah perusahaan yang meninjau spreadsheet keuangan, dan saya dapat memberitahu Anda bahwa itu bukan jenis pekerjaan yang Anda berikan kepada seorang pemula.
DeanOC
8
Tidak ada perdebatan yang berarti. Siapa pun yang menentang nama yang ditentukan belum meluangkan waktu untuk sepenuhnya memahami konsekuensi mereka. Rumus yang dinamai mungkin merupakan satu-satunya konstruksi paling mendalam dan berguna di semua Excel.
Excel Hero
10
@ brettdj: Kutipan Anda benar, tetapi Anda lupa menyebutkan bahwa itu diikuti oleh enam frasa "Kecuali ...". Salah satunya adalah: " Kecuali sebagai pengganti referensi sel dalam pengkodean makro Selalu gunakan Nama Excel sebagai pengganti referensi sel saat membuat makro. Ini untuk menghindari kesalahan yang timbul dari penyisipan baris atau kolom tambahan di mana pengkodean makro tidak lagi menunjuk ke data sumber yang dimaksud. "
Marcus Mangelsdorf
47

Saya akan memberikan jawaban singkat karena semua orang memberikan jawaban yang panjang.

Anda akan mendapatkan .pilih dan. Aktifkan setiap kali Anda merekam makro dan gunakan kembali. Ketika Anda memilih sel atau sheet, itu hanya membuatnya aktif. Mulai saat itu setiap kali Anda menggunakan referensi yang tidak memenuhi syarat seperti Range.Valuemereka hanya menggunakan sel dan lembar aktif. Ini juga bisa menjadi masalah jika Anda tidak melihat di mana kode Anda ditempatkan atau pengguna mengklik pada buku kerja.

Jadi, Anda dapat menghilangkan masalah ini dengan merujuk langsung ke sel Anda. Yang terjadi:

'create and set a range
Dim Rng As Excel.Range
Set Rng = Workbooks("Book1").Worksheets("Sheet1").Range("A1")
'OR
Set Rng = Workbooks(1).Worksheets(1).Cells(1, 1)

Atau kamu bisa

'Just deal with the cell directly rather than creating a range
'I want to put the string "Hello" in Range A1 of sheet 1
Workbooks("Book1").Worksheets("Sheet1").Range("A1").value = "Hello"
'OR
Workbooks(1).Worksheets(1).Cells(1, 1).value = "Hello"

Ada berbagai kombinasi metode ini, tetapi itu akan menjadi ide umum yang diungkapkan sesegera mungkin untuk orang-orang tidak sabar seperti saya.

MattB
sumber
33

"... dan saya menemukan bahwa kode saya akan lebih dapat digunakan kembali jika saya dapat menggunakan variabel daripada fungsi Pilih."

Sementara saya tidak bisa memikirkan lebih dari segelintir situasi di mana .Selectakan menjadi pilihan yang lebih baik daripada referensi sel langsung, saya akan bangkit untuk membela Selectiondan menunjukkan bahwa itu tidak boleh dibuang karena alasan yang sama yang .Selectharus dihindari.

Ada saat-saat ketika sub rutin makro yang pendek dan hemat waktu ditugaskan untuk kombinasi tombol-panas yang tersedia dengan ketukan beberapa tombol menghemat banyak waktu. Mampu memilih sekelompok sel untuk memberlakukan kode operasional pada karya-karya ajaib ketika berhadapan dengan data saku yang tidak sesuai dengan format data lebar-lembar kerja. Sama seperti Anda memilih grup sel dan menerapkan perubahan format, memilih grup sel untuk menjalankan kode makro khusus bisa menjadi penghemat waktu utama.

Contoh-contoh dari sub framework berbasis pemilihan:

Public Sub Run_on_Selected()
    Dim rng As Range, rSEL As Range
    Set rSEL = Selection    'store the current selection in case it changes
    For Each rng In rSEL
        Debug.Print rng.Address(0, 0)
        'cell-by-cell operational code here
    Next rng
    Set rSEL = Nothing
End Sub

Public Sub Run_on_Selected_Visible()
    'this is better for selected ranges on filtered data or containing hidden rows/columns
    Dim rng As Range, rSEL As Range
    Set rSEL = Selection    'store the current selection in case it changes
    For Each rng In rSEL.SpecialCells(xlCellTypeVisible)
        Debug.Print rng.Address(0, 0)
        'cell-by-cell operational code here
    Next rng
    Set rSEL = Nothing
End Sub

Public Sub Run_on_Discontiguous_Area()
    'this is better for selected ranges of discontiguous areas
    Dim ara As Range, rng As Range, rSEL As Range
    Set rSEL = Selection    'store the current selection in case it changes
    For Each ara In rSEL.Areas
        Debug.Print ara.Address(0, 0)
        'cell group operational code here
        For Each rng In ara.Areas
            Debug.Print rng.Address(0, 0)
            'cell-by-cell operational code here
        Next rng
    Next ara
    Set rSEL = Nothing
End Sub

Kode aktual untuk diproses dapat berupa apa saja dari satu baris hingga beberapa modul. Saya telah menggunakan metode ini untuk memulai rutinitas berjalan lama pada sel-sel pilihan yang berisi nama file buku kerja eksternal.

Singkatnya, jangan membuang Selectionkarena hubungannya yang dekat dengan .Selectdan ActiveCell. Sebagai properti lembar kerja ia memiliki banyak tujuan lain.

(Ya, saya tahu pertanyaan ini tentang .Select, bukan Selectiontapi saya ingin menghapus kesalahpahaman yang mungkin disimpulkan oleh coders VBA pemula.)


sumber
13
Selectionbisa berupa apa saja di lembar kerja jadi sebaiknya uji terlebih dahulu jenis objek sebelum menetapkannya ke variabel karena Anda secara eksplisit menyatakannya sebagai Range.
L42
29

Harap perhatikan bahwa di bawah ini saya membandingkan pendekatan Select (salah satu yang ingin dihindari OP), dengan pendekatan Range (dan ini adalah jawaban untuk pertanyaan). Jadi jangan berhenti membaca ketika Anda melihat Pilih pertama.

Itu benar-benar tergantung pada apa yang Anda coba lakukan. Pokoknya contoh sederhana bisa bermanfaat. Misalkan Anda ingin mengatur nilai sel aktif menjadi "foo". Menggunakan ActiveCell Anda akan menulis sesuatu seperti ini:

Sub Macro1()
    ActiveCell.Value = "foo"
End Sub

Jika Anda ingin menggunakannya untuk sel yang bukan yang aktif, misalnya untuk "B2", Anda harus memilihnya terlebih dahulu, seperti ini:

Sub Macro2()
    Range("B2").Select
    Macro1
End Sub

Menggunakan Ranges Anda dapat menulis makro yang lebih umum yang dapat digunakan untuk mengatur nilai sel apa pun yang Anda inginkan untuk apa pun yang Anda inginkan:

Sub SetValue(cellAddress As String, aVal As Variant)
    Range(cellAddress).Value = aVal
End Sub

Kemudian Anda dapat menulis ulang Macro2 sebagai:

Sub Macro2()
    SetCellValue "B2", "foo"
End Sub

Dan Macro1 sebagai:

Sub Macro1()
    SetValue ActiveCell.Address, "foo"
End Sub

Semoga ini bisa membantu menjernihkan semuanya.

Francesco Baruchelli
sumber
1
Terima kasih atas tanggapan yang luar biasa cepat. Jadi apakah itu berarti bahwa jika saya biasanya menambahkan sel untuk rentang, beri nama rentang, dan beralih melalui itu, saya harus langsung melompat untuk membuat array?
BiGXERO
Saya tidak yakin saya mengerti apa yang Anda maksud, tetapi Anda dapat membuat Range dengan satu instruksi (mis. Range ("B5: C14")) dan Anda bahkan dapat menetapkan nilainya secara bersamaan (jika harus sama untuk setiap sel dalam rentang), mis. Rentang ("B5: C14"). Nilai = "abc"
Francesco Baruchelli
29

Menghindari Selectdan Activatemerupakan langkah yang membuat Anda pengembang VBA sedikit lebih baik. Secara umum, Selectdan Activatedigunakan saat makro direkam, dengan demikian Parentlembar kerja atau rentang selalu dianggap sebagai yang aktif.

Ini adalah bagaimana Anda dapat menghindari Selectdan Activatedalam kasus-kasus berikut:


Menambahkan Lembar Kerja baru dan menyalin sel di atasnya:

Dari (kode yang dihasilkan dengan perekam makro):

Sub Makro2()
    Range("B2").Select
    Sheets.Add After:=ActiveSheet
    Sheets("Tabelle1").Select
    Sheets("Tabelle1").Name = "NewName"
    ActiveCell.FormulaR1C1 = "12"
    Range("B2").Select
    Selection.Copy
    Range("B3").Select
    ActiveSheet.Paste
    Application.CutCopyMode = False
End Sub

Untuk:

Sub TestMe()
    Dim ws As Worksheet
    Set ws = Worksheets.Add
    With ws
        .Name = "NewName"
        .Range("B2") = 12
        .Range("B2").Copy Destination:=.Range("B3")
    End With
End Sub

Saat Anda ingin menyalin rentang antara lembar kerja:

Dari:

Sheets("Source").Select
Columns("A:D").Select
Selection.Copy
Sheets("Target").Select
Columns("A:D").Select
ActiveSheet.Paste

Untuk:

Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").Range("a1")

Menggunakan rentang bernama mewah

Anda dapat mengaksesnya bersama [] , yang benar-benar indah, dibandingkan dengan cara lain. Periksa diri Anda:

Dim Months As Range
Dim MonthlySales As Range

Set Months = Range("Months")    
Set MonthlySales = Range("MonthlySales")

Set Months =[Months]
Set MonthlySales = [MonthlySales]

Contoh dari atas akan terlihat seperti ini:

Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").[A1]

Bukan menyalin nilai, tetapi mengambilnya

Biasanya, jika Anda mau select, kemungkinan besar Anda sedang menyalin sesuatu. Jika Anda hanya tertarik pada nilai-nilai ini, ini adalah opsi yang baik untuk menghindari pilih:

Range("B1:B6").Value = Range("A1:A6").Value


Coba selalu referensi lembar kerja juga

Ini mungkin kesalahan paling umum di . Setiap kali Anda menyalin rentang, kadang-kadang lembar kerja tidak direferensikan dan dengan demikian VBA menganggap lembar yang salah sebagai ActiveWorksheet.

'This will work only if the 2. Worksheet is selected!
Public Sub TestMe()
    Dim rng As Range
    Set rng = Worksheets(2).Range(Cells(1, 1), Cells(2, 2)).Copy
End Sub

'This works always!
Public Sub TestMe2()
    Dim rng As Range
    With Worksheets(2)
        .Range(.Cells(1, 1), .Cells(2, 2)).Copy
    End With
End Sub

Bisakah saya benar-benar tidak pernah menggunakan .Selectatau .Activateuntuk apa pun?

  • Contoh yang baik tentang kapan Anda bisa dibenarkan dalam menggunakan .Activatedan .Selectketika Anda ingin memastikan bahwa Lembar Kerja tertentu dipilih karena alasan visual. Misalnya, Excel Anda akan selalu terbuka dengan lembar kerja sampul yang dipilih terlebih dahulu, mengabaikan mana yang merupakan ActiveSheet ketika file ditutup.

Jadi, sesuatu seperti kode di bawah ini benar-benar OK:

Private Sub Workbook_Open()
    Worksheets("Cover").Activate
End Sub
Vityata
sumber
Anda dapat menggunakan Application.Goto, bukan Worksheets. Aktifkan. Agak kurang berisiko.
Geoff Griswald
1
Balasan telat FYI - contoh yang bagus dan agak tak terduga untuk kebutuhan .Select- dan juga pekerjaan saya - dapat ditemukan di Cara menulis informasi yang identik dengan semua lembar - @Vityata :)
TM
1
@ TM - memang ini adalah contoh yang menarik, dan mungkin menghemat beberapa milidetik untuk 100+ lembar kerja, tapi saya mungkin akan mencegahnya, jika saya melihatnya di suatu tempat. Pokoknya, Seleksi di sana tidak secara eksplisit ditulis tetapi hasil dari .FillAcrossSheets, jadi ini adalah di antara (setidaknya dalam ide saya tentang taksonomi VBA)
Vityata
17

Selalu nyatakan buku kerja, lembar kerja, dan sel / rentang.

Sebagai contoh:

Thisworkbook.Worksheets("fred").cells(1,1)
Workbooks("bob").Worksheets("fred").cells(1,1)

Karena pengguna akhir akan selalu hanya mengklik tombol dan segera setelah fokus berpindah dari buku kerja kode ingin bekerja dengan itu maka semuanya menjadi salah.

Dan tidak pernah menggunakan indeks buku kerja.

Workbooks(1).Worksheets("fred").cells(1,1)

Anda tidak tahu buku kerja apa yang akan dibuka saat pengguna menjalankan kode Anda.

pengguna1644564
sumber
7
Nama-nama lembar kerja bisa berubah juga, lho. Gunakan nama kode saja.
Rick mendukung Monica
Nama lembar kerja bisa berubah, tentu saja. Tapi saya tidak setuju bahwa Anda harus terlalu mempersulit kode Anda untuk mencoba dan mengurangi itu. Jika pengguna mengubah nama lembar dan makro mereka berhenti berfungsi, itu ada di sana. Saya biasanya hanya menganggap nama lembar kerja akan sama. Untuk makro yang sangat kritis, saya menjalankan sedikit pemeriksaan pra-penerbangan sebelum meluncurkan ke makro yang tepat, yang hanya memeriksa untuk memastikan semua lembar yang diharapkan untuk menemukan memang ada, dan jika ada yang hilang itu memberi tahu pengguna yang mana.
Geoff Griswald
10

Metode-metode ini agak distigmatisasi, jadi ambil pimpinan @Vityata dan @Jeeped demi menggambar garis di pasir:

Mengapa tidak memanggil .Activate, .Select, Selection, ActiveSomethingmetode / properti

Pada dasarnya karena mereka dipanggil terutama untuk menangani input pengguna melalui UI Aplikasi. Karena mereka adalah metode yang dipanggil ketika pengguna menangani objek melalui UI, mereka adalah yang direkam oleh makro-recorder, dan itulah sebabnya memanggil mereka rapuh atau berlebihan untuk sebagian besar situasi: Anda tidak harus memilih objek sehingga dapat melakukan suatu tindakan dengan Selectionsegera setelah itu.

Namun, definisi ini mengatur situasi di mana mereka dipanggil untuk:

Ketika menelepon .Activate, .Select, .Selection, .ActiveSomethingmetode / properti

Pada dasarnya ketika Anda mengharapkan pengguna akhir untuk memainkan peran dalam eksekusi.

Jika Anda mengembangkan dan mengharapkan pengguna untuk memilih objek contoh untuk menangani kode Anda, maka .Selectionatau .ActiveObjectsesuai.

Di sisi lain, .Selectdan .Activatedigunakan ketika Anda dapat menyimpulkan tindakan berikutnya pengguna dan Anda ingin kode Anda untuk memandu pengguna, mungkin menghemat beberapa waktu dan klik mouse. Misalnya, jika kode Anda baru saja membuat instance baru dari bagan atau yang diperbarui, pengguna mungkin ingin memeriksanya, dan Anda bisa memanggilnya .Activateatau lembar untuk menghemat waktu pengguna mencarinya; atau jika Anda tahu pengguna perlu memperbarui beberapa nilai rentang, Anda dapat memilih rentang itu secara terprogram.

LFB
sumber
6

Penggunaan IMHO .selectberasal dari orang-orang, yang seperti saya mulai belajar VBA dengan kebutuhan melalui perekaman makro dan kemudian memodifikasi kode tanpa menyadari bahwa .selectdan selanjutnya selectionhanyalah perantara yang tidak perlu.

.select dapat dihindari, karena sudah banyak diposting, dengan langsung bekerja dengan objek yang sudah ada, yang memungkinkan berbagai referensi tidak langsung seperti menghitung i dan j dengan cara yang kompleks dan kemudian mengedit sel (i, j), dll.

Kalau tidak, tidak ada yang salah secara implisit dengan .selectdirinya sendiri dan Anda dapat menemukan kegunaan untuk ini dengan mudah, misalnya saya memiliki spreadsheet yang saya isi dengan tanggal, mengaktifkan makro yang melakukan sihir dengannya dan mengekspornya dalam format yang dapat diterima pada lembar terpisah, yang Namun, membutuhkan beberapa input manual akhir (tidak dapat diprediksi) ke dalam sel yang berdekatan. Jadi inilah saatnya untuk .selectmenyelamatkan saya bahwa gerakan mouse tambahan dan klik.

Eleshar
sumber
2
Meskipun Anda benar, setidaknya ada satu hal yang secara implisit salah dengan pilih: lambat. Sangat lambat memang dibandingkan dengan segala sesuatu yang terjadi di makro.
vacip
4

Jawaban cepat:

Untuk menghindari menggunakan .Selectmetode ini, Anda dapat menetapkan variabel yang sama dengan properti yang Anda inginkan.

► Misalnya, jika Anda menginginkan nilai di dalamnya, Cell A1Anda bisa mengatur variabel yang sama dengan properti nilai sel itu.

  • Contoh valOne = Range("A1").Value

► Misalnya, jika Anda ingin nama kode 'Sheet3` Anda bisa mengatur variabel sama dengan properti nama kode dari lembar kerja itu.

  • Contoh valTwo = Sheets("Sheet3").Codename

Saya harap itu membantu. Beri tahu saya jika Anda memiliki pertanyaan.

FinPro.Online
sumber
3

Saya perhatikan bahwa tidak ada jawaban yang menyebutkan Properti .Offset . Ini juga dapat digunakan untuk menghindari penggunaan Selectaksi ketika memanipulasi sel tertentu, terutama dalam referensi ke sel yang dipilih (seperti OP dengan menyebutkan ActiveCell).

Berikut adalah beberapa contoh.

Saya juga akan menganggap "ActiveCell" adalah J4 .

ActiveCell.Offset(2, 0).Value = 12

  • Ini akan mengubah sel J6menjadi nilai 12
  • A minus -2 akan dirujuk J2

ActiveCell.Offset(0,1).Copy ActiveCell.Offset(,2)

  • Ini akan menyalin sel k4 ke L4.
  • Perhatikan bahwa "0" tidak diperlukan dalam parameter offset jika tidak diperlukan (, 2)
  • Mirip dengan contoh sebelumnya, minus 1 adalah i4

ActiveCell.Offset(, -1).EntireColumn.ClearContents

  • Ini akan menghapus nilai di semua sel di kolom k.

Ini bukan untuk mengatakan mereka "lebih baik" dari opsi di atas, tetapi hanya daftar alternatif.

PGSystemTester
sumber
0

Bekerja dengan fitur .Parent. Contoh ini menunjukkan bagaimana pengaturan hanya satu referensi myRng yang memungkinkan akses dinamis ke seluruh lingkungan tanpa. Pilih, .Aktifkan, .Aktifkan ponsel, .Aktifkan Buku Kerja, .Aktifkan Lembar Kerja dan sebagainya. (Tidak ada fitur .Anak genereik)

Sub ShowParents()
    Dim myRng As Range
    Set myRng = ActiveCell
    Debug.Print myRng.Address                    ' an address of the selected cell
    Debug.Print myRng.Parent.name                ' the name of sheet, where MyRng is in
    Debug.Print myRng.Parent.Parent.name         ' the name of workbook, where MyRng is in
    Debug.Print myRng.Parent.Parent.Parent.name  ' the name of application, where MyRng is in

    ' You may use this feature to set reference to these objects
    Dim mySh    As Worksheet
    Dim myWbk   As Workbook
    Dim myApp   As Application

    Set mySh = myRng.Parent
    Set myWbk = myRng.Parent.Parent
    Set myApp = myRng.Parent.Parent.Parent
    Debug.Print mySh.name, mySh.Cells(10, 1).Value
    Debug.Print myWbk.name, myWbk.Sheets.Count
    Debug.Print myApp.name, myApp.Workbooks.Count

    ' You may use dynamically addressing
    With myRng
        .Copy

       ' pastes in D1 on sheet 2 in the same workbook, where copied cell is
        .Parent.Parent.Sheets(2).Range("D1").PasteSpecial xlValues
    ' or myWbk.Sheets(2).Range("D1").PasteSpecial xlValues

       ' we may dynamically call active application too
        .Parent.Parent.Parent.CutCopyMode = False
    ' or myApp.CutCopyMode = False
    End With
End Sub
barneyos
sumber
Sangat bagus, tetapi tidak yakin apa hubungannya dengan pertanyaan OP. Anda tidak perlu "Induk" sama sekali untuk bekerja di VBA tanpa menggunakan Select atau ActiveSheet
Geoff Griswald
0

Alasan utama tidak pernah menggunakan Select atau Activesheet adalah karena kebanyakan orang akan memiliki setidaknya beberapa buku kerja terbuka (kadang-kadang lusinan) ketika mereka menjalankan makro Anda, dan jika mereka mengklik menjauh dari lembar Anda saat makro Anda berjalan dan klik beberapa lainnya buku yang telah mereka buka, lalu "Activesheet" berubah, dan buku kerja target untuk perintah "Select" yang tidak memenuhi syarat juga berubah.

Paling-paling, makro Anda akan macet, paling buruk Anda mungkin akhirnya menulis nilai atau mengubah sel di buku kerja yang salah tanpa cara untuk "Membatalkan" mereka.

Saya memiliki aturan emas sederhana yang saya ikuti: Tambahkan variabel bernama "wb" dan "ws" untuk objek Workbook dan objek Worksheet dan selalu gunakan itu untuk merujuk ke buku makro saya. Jika saya perlu merujuk lebih dari satu buku, atau lebih dari satu lembar, saya menambahkan lebih banyak variabel.

sebagai contoh

Dim wb as Workbook
Dim ws as Worksheet
Set wb = ThisWorkBook
Set ws = wb.sheets("Output")

Perintah "Set wb = ThisWorkbook" benar-benar penting. "ThisWorkbook" adalah nilai khusus di Excel, dan itu berarti buku kerja tempat Anda menjalankan kode VBA . Pintasan yang sangat membantu untuk mengatur variabel Workbook Anda.

Setelah Anda melakukannya di bagian atas Sub Anda, menggunakannya tidak bisa lebih sederhana, cukup gunakan di mana saja Anda akan menggunakan "Pilihan":

Jadi untuk mengubah nilai sel "A1" di "Output" menjadi "Hello", alih-alih:

Sheets("Output").Activate
ActiveSheet.Range("A1").Select
Selection.Value = "Hello"

Kita sekarang dapat melakukan ini:

ws.Range("A1").Value = "Hello"

Yang tidak hanya jauh lebih andal dan kecil kemungkinannya macet jika pengguna bekerja dengan banyak spreadsheet, tetapi juga jauh lebih pendek, lebih cepat dan lebih mudah untuk menulis.

Sebagai bonus tambahan, jika Anda selalu memberi nama variabel "wb" dan "ws", Anda dapat menyalin dan menempelkan kode dari satu buku ke buku lainnya dan biasanya akan bekerja dengan perubahan minimal yang diperlukan, jika ada.

Geoff Griswald
sumber
1
Bukan downvote saya, tapi saya tidak yakin ini menambahkan sesuatu yang baru untuk apa yang telah diusulkan dalam jawaban yang ada.
BigBen
Ya, jawaban saya sedikit berlebihan, tetapi jawaban lainnya terlalu panjang, mengandung terlalu banyak hal yang tidak perlu dan tidak ada yang menyebutkan menggunakan ThisWorkbook untuk mengatur variabel worksheet Anda di muka. Itu adalah sesuatu yang, jika seseorang menunjukkan saya pertama kali saya mencelupkan kaki ke VBA, saya akan menemukan sangat membantu. Orang lain telah menyebutkan menggunakan variabel Lembar Kerja tetapi tidak benar-benar menjelaskan mengapa dengan sangat baik, dan tidak menawarkan contoh kode dengan dan tanpa menggunakan variabel lembar kerja dan buku kerja.
Geoff Griswald
Tetapi jawaban yang diterima pasti membahas ThisWorkbook... Saya tidak yakin komentar Anda akurat.
BigBen
Ya, Anda tidak salah. Tetapi tidak dalam konteks menggunakannya untuk mengatur variabel buku kerja dan menggunakan variabel buku kerja itu ke depan, atau menggunakan variabel buku kerja itu untuk mengatur variabel lembar kerja, seperti yang saya sarankan. Jawaban saya lebih pendek, lebih sederhana dan lebih mudah diakses untuk pemula daripada jawaban yang diterima.
Geoff Griswald
-3

Ini adalah contoh yang akan menghapus konten sel "A1" (atau lebih jika jenis pilihannya adalah xllastcell, dll). Semua dilakukan tanpa harus memilih sel.

Application.GoTo Reference:=Workbook(WorkbookName).Worksheets(WorksheetName).Range("A1")
Range(Selection,selection(selectiontype)).clearcontents 

Saya harap ini membantu seseorang.

marionffavp
sumber
1
Tidak, maaf Itu sama sekali bukan yang Anda lakukan di sana. Apa yang sebenarnya Anda lakukan adalah memilih sel "A1" menggunakan perintah "Application.GoTo", yang tidak berbeda dengan menggunakan "Pilih", lalu menggunakan konten yang jelas pada pilihan Anda. cara untuk melakukannya tanpa memilih sel akan menjadi Workbook(WorkbookName).Worksheets(WorksheetName).Range("A1").ClearContentssatu baris dan bukan dua, dan benar-benar berfungsi tanpa memilih sel.
Geoff Griswald