返回列表 上一主題 發帖

[發問] 此巨集為何錯??

回復 29# t8899
晤...
若是會有小數出現的數值,
那就要把 CLng(  用 CSng( 來取代就可以了.

TOP

回復 43# t8899
  1. Sub nn()
  2. Dim i%
  3. Dim lRows As Long

  4. With Sheets("sheet2")
  5.   lRows = .Cells(Rows.Count, 1).End(xlUp).Row
  6.   .Cells(lRows + 1, 1) = Sheets("Sheet3").Cells(i + 1, 2).Value
  7.   '.
  8.   '.
  9.   '.
  10. End With
  11. End Sub
複製代碼

TOP

回復 46# t8899
因為漲跌兩邊都要執行,
所以會加兩行 :
  1.   Dim sStr$
  2.   Dim ZZ As Range
  3.   
  4.   sStr = ""
  5.   sStr2 = ""
  6.   For Each ZZ In Range("c2:c111")
  7.     If Not IsError(ZZ) Then
  8.       If Range("Q26").Value = 1 And flag = True Then
  9.         M = Round(ZZ - ZZ.Offset(, 26), 2)
  10.         If M >= ZZ.Offset(, 2) Then
  11.           If sStr <> "" Then sStr = sStr & Chr(10)
  12.           sStr = sStr & "" & Cells(ZZ.Row, 2).Value & "=====> " _
  13.                  & Round(ZZ - ZZ.Offset(, 26), 2)
  14.           ZZ.Offset(, 26) = ZZ ' <======= 加在這裡
  15.         End If
  16.         If M <= -ZZ.Offset(, 2) Then
  17.           If sStr2 <> "" Then sStr2 = sStr2 & Chr(10)
  18.           sStr2 = sStr2 & "" & Cells(ZZ.Row, 2).Value & "=====> " _
  19.                    & Round(ZZ - ZZ.Offset(, 26), 2)
  20.           ZZ.Offset(, 26) = ZZ ' <======= 加在這裡
  21.         End If
  22.       End If
  23.     End If
  24.   Next
  25.   If sStr <> "" Then
  26.     CreateObject("Wscript.shell").Popup sStr, 4, "Auto Closed MsgBox", 64
  27.   End If
  28.   If sStr2 <> "" Then
  29.     CreateObject("Wscript.shell").Popup sStr2, 4, "Auto Closed MsgBox", 64
  30.   End If
複製代碼
另外,建議你可以參考類似上面這樣有做縮排處理的程式編寫習慣,
只需先找到區塊的某一邊,
直接按上或下鍵就能確認區塊的範圍,
這樣要找問題或是切入點會比較容易,
也比較不容易因為要找一些缺東缺西的問題而浪費寫程式的時間.

TOP

本帖最後由 luhpro 於 2013-8-17 09:14 編輯
ZZ.Offset(, 26) ====>可否直接改成AC欄的語法??
t8899 發表於 2013-8-16 18:47
訊息無法一次出現???會一隻一隻出現??
t8899 發表於 2013-8-15 22:07

那是因為跑 ZZ.Offset(, 26) = ZZ 這一行指令時又會觸發 Calculate 事件,
導致又再一次進入了  Worksheet_Calculate 函式.
只要在執行此行指令時把觸發功能暫時禁能即可 :
將兩個
  ZZ.Offset(, 26) = ZZ
都改成
Application.EnableEvents = False
  ZZ.Offset(, 26) = ZZ
Application.EnableEvents = True
即可

ZZ.Offset(, 26) ====>可否直接改成AC欄的語法??
t8899 發表於 2013-8-16 18:47

Range.Offset 指令是傳回 :
以該Range為基準,
位移Offset右方括弧內所指定的列數與欄數後的儲存格位址.

此函式傳回的是個 "相對" 位置,
自然就不能用AC欄的語法啦.

ZZ.Offset(, 26)
就等於
Range(ZZ.Row, ZZ.Column + 26)

若堅持要改成AC欄語法勉強可以改為
Range("AC" & CStr(ZZ.Row))
因為列號是須要參考ZZ而做變動的,
而若日後你的 ZZ 改成不在 "C" 欄時,
上式傳回的位址就又不正確了.

TOP

巨集裡的公式,好像不會跟著工作表變動參照??
例如 If Range("Q2").Value = 1
我在P欄插入一欄,巨集不 ...
t8899 發表於 2013-8-18 09:11

巨集�堛熊{式片斷與儲存格本來就不是綁在一起而是各自獨立的,
Range("Q2") 永遠就是指 Q2 這個儲存格,
而在其右邊的 .Offset(xx,yy) 也只能對應到唯一一個儲存格,
而上列兩個儲存格並不會因為你在其前方插入欄列而跟著變動.

若需要相應的跟著儲存格做變動,
比較可行的方法我能想到的有兩種:
1. 在某個儲存格內下公式去參照到標的儲存格,而 Excel VBA 程式則透過參照位址做處理.(前提是不論怎麼插入欄列,都不能變動到參照儲存格的位置)
可藉由 Range(Mid(Cells(3,1).Formula,2)).Row 取得列號
可藉由 Range(Mid(Cells(3,1).Formula,2)).Column  取得欄號.

2. 對標的儲存格定義名稱,而 Excel VBA 程式則透過該名稱的位址做處理.
例如:
** 定義名稱為 Work 參照到 =Sheet1!$A$4
在 With ActiveWorkbook.Names("Work")  與 End With 之間:
可用 .Value 抓到 =Sheet1!$A$4 等文字,
再用 Range( Mid(.Value, InStr(1, .Value, "!") + 1)).Row 可抓到列號.
Range( Mid(.Value, InStr(1, .Value, "!") + 1)).Column 可抓到欄號.

TOP

本帖最後由 luhpro 於 2013-8-22 23:58 編輯
1.之前的問題,經再測試無法自動關掉訊息窗
是因為跑下面的程式,不知有無辦法改善?
好像只要有在跑ti ...
t8899 發表於 2013-8-22 04:35

1. 這我也不知道,不過據我所知 Excel VBA 畢竟不是單純的 VB 系統,
在某些情形下還是會發生某些我們覺得不太能理解的狀況.

最簡單的例子是若某時間有開了兩個 Excel 檔案,其中一個有 Excel VBA 程式的檔案,
有可能會干擾到另一個沒有 VBA 程式檔案的編輯作業.(尤其是 Worksheet_Change 與 Worksheet_SelectionChange 程序最易發生此狀況)

依你的敘述看起來,
它可能不能同時執行太多的 Application.OnTime 程式.(疑似會有相互干擾的情形出現)

當然這個就是很內部的東西了,
當 Excel VBA 每呼叫一次 Application.OnTime 程式,
是否就會配置一個程序空間來存放該程式運作中的變數,
直到該程式結束才釋放掉該空間?
亦或是只要是執行該程式,
就都是使用同一個程序空間裡的變數呢?
若是後者那出現你說的情形應該就不意外了.

而若真要是這個問題也是有方法解決的啦,
只要 "每個" 呼叫的程式都不同就不會互相干擾了,
亦即要確保同一時間在跑的 OnTime 程式都是在不同程式區塊中即可.
可不可行我不知道你可以試試看.

2. 與上方的定義內容一一比對即可知道錯誤出在哪裡了:
你的呼叫程式為 :

MsgBoxTest 0, "", "", sStr, 0, 2500

而其定義則為 :
Private Declare Function MsgBoxTest Lib "user32" Alias "MessageBoxTimeoutA" ( _
    ByVal hwnd As Long, _                 <=== 上面的 0 ,   OK
    ByVal lpText As String, _              <=== 上面的 "",   OK
    ByVal lpCaption As String, _          <=== 上面的 "",   OK
    ByVal wType As VbMsgBoxStyle, _ <=== 上面的 sStr, 錯誤出在此
   ByVal wlange As Long, _              <=== 上面的 0,    OK
    ByVal dwTimeout As Long _          <=== 上面的 2500, OK
                           ) As Long

至於 VbMsgBoxStyle?
在 http://www.codeproject.com/Articles/7914/MessageBoxTimeout-API
上看到 : uiFlags = MB_YESNO|MB_SETFOREGROUND|MB_SYSTEMMODAL|MB_ICONINFORMATION
且
http://www.pinvoke.net/default.aspx/user32/MessageBoxTimeout.html?diff=y
上看到該參數可定義為 ByVal MessageBoxOptions As Long
所以至少那應該是個數字而非文字才是,
而在 http://baike.baidu.com/view/5079352.htm
這裡有詳細說明各個數值的定義.

至於 sStr 則應放在 lpText As String 上.

綜上你可以試試 :

MsgBoxTest 0, sStr, "提示訊息", 0, 0, 2500

3. FindWindow 要先知道該視窗的 handle 或是 足資辨識該視窗的資料才能找到該視窗,
這個我要再查查看是否有可能解決.

TOP

謝謝已經解決
MsgBoxTest 會自動關閉視窗,應該是MsgBoxTest獨立在跑
有兩個小缺點
1有時提示時無法在最前景??
2提示時,會出現漏斗狀,沒辦法做其他事情,但沒差,只有幾秒而已
t8899 發表於 2013-8-23 09:13

1. 本來若你用的是 MsgBox 函數, 則在 MsgBox 函數 的說明中有寫到 :
語法
MsgBox(prompt[, buttons] [, title] [, helpfile, context])
buttons 引數的設定有以下幾個:
其中有 :
VbMsgBoxSetForeground 65536 指定訊息方塊視窗作為前景視窗。
亦即你程式只要在 第二個參數加上 + VbMsgBoxSetForeground 即可讓此訊息顯示在最上層.
但如今你用的是另一個Windows API函數,
這個函數我找不到哪裡有較詳細的說明,
所以就需要你自己測試看看該函數是否有這個功能了.

2. 同上,這個問題我也不知道如何處理.

TOP

p.s. (65536 無法放在VbMsgBoxSetForeground 後面,語法錯誤)
t8899 發表於 2013-8-27 06:14

65536 放在 VbMsgBoxSetForeground 後面?
當然會發生錯誤啦.

說明中的內文是 :

             常數                       值                       說明
====================================================
VbMsgBoxSetForeground      65536     指定訊息方塊視窗作為前景視窗。

它的意思是說 :
在 Excel VBA 中, 已經有定義了 VbMsgBoxSetForeground 這個常數的值為 65536,
你在 MsgBox 函數的 buttons 引數的位置上,
可以使用 VbMsgBoxSetForeground 這個常數 或是用 65536 這個值(任取其中之一),
來設定這次使用 MsgBox 函數 指定其 訊息方塊視窗 作為前景視窗.

你也可以參考 MsgBox 的範例得知其使用方式:
Style = vbYesNo + vbCritical + vbDefaultButton2    ' 定義按鈕。
Response = MsgBox(Msg, Style, Title, Help, Ctxt)
參照範例可得出你可以使用 :
MsgBox sStr, vbYesNo + VbMsgBoxSetForeground , "提示訊息"
或是
MsgBox sStr, 4 + 65536 , "提示訊息" (左式也等同 MsgBox sStr, 65540 , "提示訊息")
上兩式的結果是相同的.

不過 MsgBox 函數可以使用的常數不一定就適用 MsgBoxTest (在 Windows API 中它其實應該是 MessageBoxTimeoutA),
這要看在 Windows API 與 Excel VBA 中,
MessageBoxTimeoutA 函數是否有實做出該引數為 VbMsgBoxSetForeground 值時所應該出現的效果,
最簡單的方法就是套用進程式中,
然後實際跑跑看就知道有沒有此功能了.

TOP

Sub eighty()
         ...
Range("B2:N2").Select   '=====>為何多加此行,造成上面的執行不正確,拿掉則正確????
t8899 發表於 2013-8-28 06:49

這行是我加的嗎?
我沒有印象有加這行啊?

現在我已經很少用 Select 指令了,
除非確有其必要性,(例如需要用到 Selection 做指令主體, 或是需要變更Excel檔案焦點到另一個主體上)
否則這行除了浪費系統資源外,
並沒有什麼其他好處,
很多情形下其實是根本不需用到 Select 指令就可以達到我們的目的.

不過這個指令在 Debug 程式時倒是滿好用的,
例如想 Copy 時,
可以先不真的 Copy 而可以使用 F8  單步模式追蹤,
執行 Copy 前先在即時視窗用 Select 來確認欲運作的標的是否正確.

因為你的 Sample 檔不能判斷該行用處在哪及拿掉是否會出問題,
所以你只能自行測試或判斷,
你若是確定加了該指令對程式結果沒什麼用處的話,
那就乾脆直接刪掉該行吧. (你也可以先在該行前面加個  '   把它變成註解文字, 該行就不會執行了, 反之就又會執行了)

TOP

        靜思自在 : 犯錯出懺悔心,才能清淨無煩惱。
返回列表 上一主題