Excel VBA'da Seç kullanmaktan nasıl kaçınılır
.Select
Excel VBA'da kullanımın anlaşılır iğrençliği hakkında çok şey duydum , ancak onu kullanmaktan nasıl kaçınacağımdan emin değilim. Select
İşlevler yerine değişkenleri kullanabilseydim kodumun daha fazla yeniden kullanılabilir olacağını görüyorum . Ancak, ActiveCell
kullanmıyorsam şeylere ( vb.) Nasıl atıfta bulunacağımdan emin değilim Select
.
Bu makaleyi aralıklarla buldum ve bu örneği select kullanmamanın faydaları üzerine buldum , ancak nasıl olduğuna dair hiçbir şey bulamıyorum .
Yanıtlar
Seçimden nasıl kaçınılacağına dair bazı örnekler
Dim
'D değişkenlerini kullanın
Dim rng as Range
Set
değişken gerekli aralığa. Tek hücreli bir aralığı ifade etmenin birçok yolu vardır:
Set rng = Range("A1")
Set rng = Cells(1, 1)
Set rng = Range("NamedRange")
Veya çok hücreli bir aralık:
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)
Sen edebilirsiniz kısayol kullanmak Evaluate
yöntemle, ancak bu daha az verimlidir ve genellikle üretim kodunda kaçınılmalıdır.
Set rng = [A1]
Set rng = [A1:B10]
Yukarıdaki tüm örnekler, aktif sayfadaki hücrelere atıfta bulunmaktadır . Özellikle yalnızca etkin sayfayla çalışmak istemediğiniz sürece, bir Worksheet
değişkeni de boyutlandırmak daha iyidir :
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
Eğer varsa do çalışmak isteyen ActiveSheet
, netlik için o açık olmak en iyisidir. Ancak bazı Worksheet
yöntemler aktif sayfayı değiştirdiği için dikkatli olun .
Set rng = ActiveSheet.Range("A1")
Yine, bu aktif çalışma kitabını ifade eder . Yalnızca ActiveWorkbook
veya ile çalışmak istemediğiniz sürece ThisWorkbook
, bir Workbook
değişkeni Dim etmek daha iyidir .
Dim wb As Workbook
Set wb = Application.Workbooks("Book1")
Set rng = wb.Worksheets("Sheet1").Range("A1")
Eğer varsa do çalışmak isteyen ActiveWorkbook
, netlik için o açık olmak en iyisidir. Ancak, birçok WorkBook
yöntem aktif kitabı değiştirdiği için dikkatli olun .
Set rng = ActiveWorkbook.Worksheets("Sheet1").Range("A1")
ThisWorkbook
Nesneyi, çalışan kodu içeren kitaba başvurmak için de kullanabilirsiniz .
Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A1")
Yaygın (kötü) bir kod parçası, bir kitabı açmak, biraz veri almak ve tekrar kapatmaktır.
Bu kötü:
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
Ve şöyle daha iyi olurdu:
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
Aralık değişkenleri olarak Sub
e ve s'lerinize aralıkları geçirin Function
:
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
Ayrıca değişkenlere Yöntemler ( Find
ve gibi Copy
) uygulamalısınız:
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
Bir hücre aralığı üzerinde döngü yapıyorsanız, aralık değerlerini önce bir varyant diziye kopyalayıp bunun üzerinden geçmek genellikle daha iyidir (daha hızlıdır):
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
Bu, mümkün olanın küçük bir çeşididir.
İki ana nedenleri .Select
, .Activate
, Selection
, Activecell
, Activesheet
, Activeworkbook
, vb kaçınılmalıdır
- Kodunuzu yavaşlatır.
- Genellikle çalışma zamanı hatalarının ana nedenidir.
Bundan nasıl kaçınırız?
1) İlgili nesnelerle doğrudan çalışın
Bu kodu düşünün
Sheets("Sheet1").Activate
Range("A1").Select
Selection.Value = "Blah"
Selection.NumberFormat = "@"
Bu kod şu şekilde de yazılabilir:
With Sheets("Sheet1").Range("A1")
.Value = "Blah"
.NumberFormat = "@"
End With
2) Gerekirse değişkenlerinizi belirtin. Yukarıdaki aynı kod şu şekilde yazılabilir:
Dim ws as worksheet
Set ws = Sheets("Sheet1")
With ws.Range("A1")
.Value = "Blah"
.NumberFormat = "@"
End With
Daha önce verilen tüm mükemmel cevaplara ekleyeceğim küçük bir vurgu noktası:
Muhtemelen Select'i kullanmaktan kaçınmak için yapabileceğiniz en büyük şey , VBA kodunuzda adlandırılmış aralıkları (anlamlı değişken adlarıyla birlikte) kullanmaktır . Bu noktadan yukarıda bahsedilmişti, ancak biraz üzerinde parlatılmıştı; ancak, özel ilgiyi hak ediyor.
Burada, adlandırılmış aralıkları özgürce kullanmak için birkaç ek neden var, ancak daha fazlasını düşünebileceğime eminim.
Adlandırılmış aralıklar, kodunuzun okunmasını ve anlaşılmasını kolaylaştırır.
Misal:
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
Bu Ne adlandırılmış aralıklar oldukça açıktır Months
ve MonthlySales
içerirler ve prosedür ne yaptığını.
Bu neden önemli? Kısmen başkalarının anlaması daha kolay olduğu için, ancak kodunuzu görecek veya kullanacak tek kişi siz olsanız bile, adlandırılmış aralıkları ve iyi değişken adlarını kullanmalısınız çünkü onunla ne yapmak istediğinizi unutacaksınız . bir yıl sonra ve sadece kodunuzun ne yaptığını bulmak için 30 dakika harcayacaksınız .
Adlandırılmış aralıklar, elektronik tablonun yapılandırması değiştiğinde (değilse!) Makrolarınızın bozulmamasını sağlar.
Yukarıdaki örnek şu şekilde yazılmışsa düşünün:
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
Bu kod ilk başta gayet iyi çalışacak - ta ki siz veya gelecekteki bir kullanıcı "gee wiz, Sanırım Sütun'a yıl ile yeni bir sütun ekleyeceğim A
!" Veya aylar arasına bir giderler sütunu ekleyene kadar. satış sütunları veya her sütuna bir başlık ekleyin. Şimdi, kodunuz bozuldu. Ve berbat değişken isimleri kullandığınız için, onu nasıl düzelteceğinizi anlamanız gerekenden çok daha fazla zaman alacaktır.
Başlamak için adlandırılmış aralıklar kullandıysanız, Months
ve Sales
sütunları istediğiniz kadar hareket ettirilebilir ve kodunuz iyi çalışmaya devam ederdi.
Herkes uzun cevabı verdiği için kısa cevabı vereceğim.
Makroları her kaydedip yeniden kullandığınızda .select ve .activate elde edersiniz. Bir hücre veya sayfayı seçtiğinizde, onu aktif hale getirir. Bu noktadan itibaren, Range.Value
sadece aktif hücre ve sayfayı kullanıyorlarmış gibi, niteliksiz referanslar kullandığınızda. Bu, kodunuzun nereye yerleştirildiğini izlemiyorsanız veya bir kullanıcı çalışma kitabını tıkladığında da sorunlu olabilir.
Böylece, hücrelerinize doğrudan başvurarak bu sorunları ortadan kaldırabilirsiniz. Hangisi:
'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)
Ya da yapabilirsin
'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"
Bu yöntemlerin çeşitli kombinasyonları var ama benim gibi sabırsız insanlar için olabildiğince kısa sürede ifade edilen genel fikir bu olacaktır.
"... ve Seç işlevleri yerine değişkenleri kullanabilseydim kodumun daha yeniden kullanılabilir olacağını anlıyorum."
.Select
Doğrudan hücreye atıfta bulunmaktan daha iyi bir seçim olacak izole bir avuç durumdan fazlasını düşünemiyorum , savunmaya yükselir Selection
ve .Select
kaçınılması gereken aynı nedenlerle atılmaması gerektiğini belirtirim .
Birkaç tuşa dokunarak kullanılabilen kısayol tuş kombinasyonlarına atanmış kısa, zaman kazandıran makro alt rutinlerine sahip olunması çok zaman kazandırır. Operasyonel kodu uygulamak için bir hücre grubu seçebilmek, çalışma sayfası genelindeki bir veri formatına uymayan cepli verilerle uğraşırken harikalar yaratır. Bir hücre grubunu seçip bir biçim değişikliği uygulamanıza çok benzer şekilde, özel makro kodunun çalıştırılacağı bir hücre grubu seçmek büyük bir zaman tasarrufu sağlayabilir.
Seçim tabanlı alt çerçeve örnekleri:
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
İşlenecek gerçek kod, tek bir satırdan birden çok modüle kadar herhangi bir şey olabilir. Bu yöntemi, harici çalışma kitaplarının dosya adlarını içeren düzensiz bir hücre seçimi üzerinde uzun süre çalışan rutinler başlatmak için kullandım.
Kısacası, atmayın Selection
nedeniyle ile yakın ilişkiye .Select
ve ActiveCell
. Bir çalışma sayfası özelliği olarak başka birçok amacı vardır.
(Evet, bu sorunun .Select
bununla ilgili olduğunu biliyorum , Selection
ancak acemi VBA kodlayıcılarının çıkarabileceği yanlış anlamaları ortadan kaldırmak istedim.)
Kaçınmak Select
ve Activate
sizi biraz daha iyi VBA geliştiricisi yapan harekettir. Genel olarak Select
ve Activate
bir makro kaydedildiğinde kullanılır, bu nedenle Parent
çalışma sayfası veya aralık her zaman etkin olan olarak kabul edilir.
Bu kaçınmak nasıl olduğunu Select
ve Activate
aşağıdaki durumlarda:
Yeni bir Çalışma Sayfası eklemek ve üzerine bir hücre kopyalamak:
Gönderen (makro kaydedici ile oluşturulan kod):
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
Kime:
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
Çalışma sayfaları arasında aralığı kopyalamak istediğinizde:
Kimden:
Sheets("Source").Select
Columns("A:D").Select
Selection.Copy
Sheets("Target").Select
Columns("A:D").Select
ActiveSheet.Paste
Kime:
Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").Range("a1")
Süslü adlandırılmış aralıkları kullanma
[]
Diğer yolla kıyaslandığında gerçekten güzel olan bunlara erişebilirsiniz . Kendini kontrol et:
Dim Months As Range
Dim MonthlySales As Range
Set Months = Range("Months")
Set MonthlySales = Range("MonthlySales")
Set Months =[Months]
Set MonthlySales = [MonthlySales]
Yukarıdaki örnek şöyle görünecektir:
Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").[A1]
Değerleri kopyalamak değil, onları almak
Genellikle, eğer istekliysen select
, büyük olasılıkla bir şeyler kopyalıyorsun. Yalnızca değerlerle ilgileniyorsanız, bu, aşağıdakileri seçmekten kaçınmak için iyi bir seçenektir:
Range("B1:B6").Value = Range("A1:A6").Value
Her zaman Çalışma Sayfasına da başvurmaya çalışın
Bu muhtemelen vba'daki en yaygın hatadır . Aralıkları kopyaladığınızda, bazen çalışma sayfasına başvurulmaz ve bu nedenle VBA, ActiveWorksheet'in yanlış sayfasını değerlendirir.
'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
Gerçekten hiç kullanmıyorum Can .Select
veya .Activate
herhangi bir şey için?
- Görsel nedenlerle belirli bir Çalışma Sayfasının seçildiğinden emin olmak istediğinizde
.Activate
ve.Select
kullanımda haklı çıkabileceğiniz iyi bir örnek . Örneğin, dosya kapatıldığında ActiveSheet'in hangisi olduğu dikkate alınmaksızın, Excel'iniz her zaman ilk önce seçilen kapak çalışma sayfasıyla açılacaktır.
Bu nedenle, aşağıdaki kod gibi bir şey kesinlikle uygundur:
Private Sub Workbook_Open()
Worksheets("Cover").Activate
End Sub
Bir başka iyi örnek, bu durumda belirtildiği gibi, tüm sayfaları tek bir PDF dosyasına aktarmanız gerektiğinde - Bu örnekte VBA'da seçme / etkin ifadelerden nasıl kaçınılır?
Bir komut yalnızca ActiveWindow.Zoom veya ActiveWindow.FreezePanes
ActiveWindow
gibi çalıştığında
Lütfen aşağıda Seçim yaklaşımını (OP'nin kaçınmak istediği yaklaşım) Menzil yaklaşımıyla (ve bu sorunun cevabı) karşılaştırdığımı unutmayın. Bu yüzden ilk Seçimi gördüğünüzde okumayı bırakmayın.
Gerçekten ne yapmaya çalıştığınıza bağlı. Her neyse, basit bir örnek faydalı olabilir. Aktif hücrenin değerini "foo" olarak ayarlamak istediğinizi varsayalım. ActiveCell kullanarak şöyle bir şey yazarsınız:
Sub Macro1()
ActiveCell.Value = "foo"
End Sub
Etkin olmayan bir hücre için kullanmak istiyorsanız, örneğin "B2" için, önce şu şekilde seçmelisiniz:
Sub Macro2()
Range("B2").Select
Macro1
End Sub
Aralıkları kullanarak, istediğiniz herhangi bir hücrenin değerini istediğiniz gibi ayarlamak için kullanılabilecek daha genel bir makro yazabilirsiniz:
Sub SetValue(cellAddress As String, aVal As Variant)
Range(cellAddress).Value = aVal
End Sub
Ardından, Macro2'yi şu şekilde yeniden yazabilirsiniz:
Sub Macro2()
SetCellValue "B2", "foo"
End Sub
Ve Macro1 as:
Sub Macro1()
SetValue ActiveCell.Address, "foo"
End Sub
Daima çalışma kitabını, çalışma sayfasını ve hücreyi / aralığı belirtin.
Örneğin:
Thisworkbook.Worksheets("fred").cells(1,1)
Workbooks("bob").Worksheets("fred").cells(1,1)
Çünkü son kullanıcılar her zaman yalnızca düğmelere tıklar ve odak çalışma kitabından ayrılır ayrılmaz kod çalışmak ister ve işler tamamen ters gider.
Ve asla bir çalışma kitabının dizinini kullanmayın.
Workbooks(1).Worksheets("fred").cells(1,1)
Kullanıcı kodunuzu çalıştırdığında başka hangi çalışma kitaplarının açılacağını bilmiyorsunuz.
Bu yöntemler daha çok damgalandı, bu yüzden kuma bir çizgi çekmek uğruna Vityata ve Jeeped'in liderliğini üstleniyor :
Çağrı .Activate
, .Select
, Selection
, ActiveSomething
yöntemler / özellikler
Temel olarak, öncelikle uygulama kullanıcı arayüzü aracılığıyla kullanıcı girişini işlemek için çağrıldıkları için. Kullanıcı UI aracılığıyla nesneleri işlediğinde çağrılan yöntemler olduklarından, bunlar makro kaydedici tarafından kaydedilenlerdir ve bu yüzden çoğu durumda onları çağırmak ya kırılgan ya da gereksizdir: bir Selection
hemen ardından bir eylem gerçekleştirmek için nesne .
Bununla birlikte, bu tanım, çağrıldıkları durumları belirler:
Çağırmak zaman .Activate
, .Select
, .Selection
, .ActiveSomething
yöntemler / özellikler
Temel olarak, son kullanıcının yürütmede bir rol oynamasını beklediğinizde .
Geliştiriyorsanız ve kullanıcının kodunuzun işleyeceği nesne örneklerini seçmesini bekliyorsanız, o zaman .Selection
veya .ActiveObject
uygun olur.
Öte yandan, .Select
ve .Activate
kullanıcının bir sonraki eylemi çıkarabiliriz zaman kullanım ve muhtemelen onu / ona biraz zaman ve fare tıklamaları tasarruf kodunuzu kullanıcıya rehberlik etmek istiyorum. Örneğin, kodunuz bir grafiğin yepyeni bir örneğini oluşturduysa veya güncellediyse, kullanıcı onu kontrol etmek isteyebilir .Activate
ve kullanıcıyı arama zamanından kurtarmak için onu veya sayfasını çağırabilirsiniz ; veya kullanıcının bazı aralık değerlerini güncellemesinin gerekeceğini biliyorsanız, bu aralığı programlı olarak seçebilirsiniz.
IMHO kullanımı, .select
benim gibi VBA'yı zorunlu olarak makroları kaydederek öğrenmeye başlayan ve daha sonra bunun farkına varmadan kodu değiştiren .select
ve sonrasında selection
sadece gereksiz bir aracı olan insanlardan geliyor.
.select
Halihazırda gönderilmiş olduğu gibi, zaten var olan nesnelerle doğrudan çalışarak, i ve j'yi karmaşık bir şekilde hesaplamak ve ardından hücreyi (i, j) düzenlemek vb.
Aksi takdirde, .select
kendisinde dolaylı olarak yanlış olan hiçbir şey yoktur ve bunun kullanımlarını kolayca bulabilirsiniz, örneğin tarihle doldurduğum bir elektronik tablom var, onunla biraz sihir yapan makroyu etkinleştirin ve kabul edilebilir bir biçimde ayrı bir sayfada dışa aktaran bir elektronik tablom var. ancak bitişik bir hücreye bazı son manuel (öngörülemeyen) girdiler gerektirir. İşte .select
bunun için an geldi , bana ek fare hareketi ve tıklama tasarrufu sağlıyor.
.Select
Yöntemi kullanmaktan kaçınmak için, istediğiniz özelliğe eşit bir değişken ayarlayabilirsiniz.
► Örneğin, içindeki değeri istiyorsanız, Cell A1
o hücrenin değer özelliğine eşit bir değişken ayarlayabilirsiniz.
- Misal
valOne = Range("A1").Value
► Örneğin you could set a variable equal to the
, o çalışma sayfasının 'Sayfa3 Kod Adı` özelliğinin kod adını istiyorsanız .
- Misal
valTwo = Sheets("Sheet3").Codename
Bu yanıtların hiçbirinin .Offset Özelliğinden bahsetmediğini fark ettim . Bu aynı zamanda Select
, özellikle seçilen bir hücreye atıfta bulunarak (OP'nin bahsettiği gibi ActiveCell
) belirli hücreleri işlerken eylemi kullanmaktan kaçınmak için de kullanılabilir .
İşte birkaç örnek.
Ayrıca "ActiveCell" in J4 olduğunu varsayacağım .
ActiveCell.Offset(2, 0).Value = 12
- Bu, hücreyi
J6
12 değerine değiştirecek - Eksi -2, J2'ye başvururdu
ActiveCell.Offset(0,1).Copy ActiveCell.Offset(,2)
- Bu hücreyi kopyalar
k4
içinL4
. - Gerekmiyorsa ofset parametresinde "0" gerekmediğine dikkat edin (, 2)
- Önceki örneğe benzer şekilde eksi 1,
i4
ActiveCell.Offset(, -1).EntireColumn.ClearContents
- Bu, k sütunundaki tüm hücrelerdeki değerleri temizleyecektir.
Bunlar, yukarıdaki seçeneklerden "daha iyi" oldukları anlamına gelmez, sadece alternatifleri listeler.
Kopyala-yapıştır nasıl önlenir?
Kabul edelim: bu, makroları kaydederken çok görünür:
Range("X1").Select
Selection.Copy
Range("Y9).Select
Selection.Paste
Kişinin istediği tek şey şudur:
Range("Y9").Value = Range("X1").Value
Bu nedenle, VBA makrolarında kopyala-yapıştır kullanmak yerine aşağıdaki basit yaklaşımı öneririm:
Destination_Range.Value = Source_Range.Value
.Parent özelliğiyle çalışan bu örnek, yalnızca bir myRng referansının ayarlanmasının herhangi bir .Select, .Activate, .Activecell, .ActiveWorkbook, .ActiveSheet vb. Olmadan tüm ortama nasıl dinamik erişim sağladığını gösterir. (Herhangi bir jenerik .Child özelliği yoktur.)
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 the 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
Seç veya Etkin Sayfayı hiçbir zaman kullanmamanın ana nedeni, çoğu insanın makronuzu çalıştırdıklarında en az birkaç çalışma kitabının (bazen düzinelerce) açık olması ve makronuz çalışırken sayfanızdan uzağa tıklarlarsa ve başka bir sayfaya tıklarlarsa olmasıdır. Açtıkları kitap, ardından "Etkin Sayfa" değişir ve nitelenmemiş "Seç" komutu için hedef çalışma kitabı da değişir.
En iyi durumda, makronuz çökecektir, en kötü ihtimalle, yanlış çalışma kitabındaki değerleri "Geri Almanın" hiçbir yolu olmadan değerleri yazmaya veya hücreleri değiştirmeye başlayabilirsiniz.
Takip ettiğim basit bir altın kuralı var: Bir Çalışma Kitabı nesnesi ve bir Çalışma Sayfası nesnesi için "wb" ve "ws" adlı değişkenler ekleyin ve bunları her zaman makro kitabıma başvurmak için kullanın. Birden fazla kitaba veya birden fazla sayfaya başvurmam gerekirse, daha fazla değişken eklerim.
Örneğin,
Dim wb as Workbook
Dim ws as Worksheet
Set wb = ThisWorkBook
Set ws = wb.sheets("Output")
"Set wb = ThisWorkbook" komutu kesinlikle anahtardır. "ThisWorkbook", Excel'de özel bir değerdir ve VBA kodunuzun şu anda çalıştığı çalışma kitabı anlamına gelir . Çalışma Kitabı değişkeninizi ile ayarlamak için çok yararlı bir kısayol.
Aboneliğinizin üst kısmında bunu yaptıktan sonra, onları kullanmak daha kolay olamazdı, "Seçim" i kullandığınız her yerde kullanın:
Dolayısıyla, "Çıktı" daki "A1" hücresinin değerini "Merhaba" olarak değiştirmek için:
Sheets("Output").Activate
ActiveSheet.Range("A1").Select
Selection.Value = "Hello"
Şimdi bunu yapabiliriz:
ws.Range("A1").Value = "Hello"
Kullanıcı birden çok elektronik tablo ile çalışıyorsa, bu yalnızca çok daha güvenilir değildir ve çökme olasılığı daha düşük değildir; ayrıca çok daha kısa, daha hızlı ve yazması daha kolay.
Ek bir bonus olarak, değişkenlerinizi her zaman "wb" ve "ws" olarak adlandırırsanız, kodu bir kitaptan diğerine kopyalayıp yapıştırabilirsiniz ve bu, varsa, genellikle minimum değişiklikle çalışacaktır.