返回列表 上一主題 發帖

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

回復  t8899
因為漲跌兩邊都要執行,
所以會加兩行 :另外,建議你可以參考類似上面這樣有做縮排處理的程式 ...
luhpro 發表於 2013-8-15 21:47

抱歉 上一樓檔案有誤,請用這個檔案測試
TEST.rar (22.42 KB)

TOP

ZZ.Offset(, 26) ====>可否直接改成AC欄的語法??

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

本帖最後由 t8899 於 2013-8-18 09:21 編輯
若堅持要改成AC欄語法勉強可以改為
Range("AC" & CStr(ZZ.Row))
因為列號是須要參考ZZ而做變動的,
而若日後你的 ZZ 改成不在 "C" 欄時,
上式傳回的位址就又不正確了.
luhpro 發表於 2013-8-17 09:11

巨集裡的公式,好像不會跟著工作表變動參照??
例如 If Range("Q2").Value = 1
我在P欄插入一欄,巨集不會自動改為 If Range("R2").Value = 1 ?
如果要跟著變動改為
IF Range("Q2").Offset(, 0) = 1  ?是這樣嗎?

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

本帖最後由 t8899 於 2013-8-22 04:47 編輯
巨集裏的程式片斷與儲存格本來就不是綁在一起而是各自獨立的,
Range("Q2") 永遠就是指 Q2 這個儲存格,
...
luhpro 發表於 2013-8-19 22:20


1.之前的問題,經再測試無法自動關掉訊息窗
是因為跑下面的程式,不知有無辦法改善?
好像只要有在跑time 的程式,就會這樣
Sub a123()
If [U1] <> 1 Then
On Error Resume Next
Application.OnTime EarliestTime:=TimeValue(Runtime), _
    Procedure:="a123", Schedule:=False
  Exit Sub
On Error GoTo 0
End If
zzzzz
If Range("V14") = 1 Then mytime = "00:01:00"
If Range("V14") = 2 Then mytime = "00:02:00"
If Range("V14") = 3 Then mytime = "00:00:30"
Runtime = Now + TimeValue(mytime)
Application.OnTime Runtime, "Sheet6.a123"
End Sub

2.後來找了一個API(MsgBoxTest)套用,代替CreateObject("Wscript.shell").Popup,
有問題??型態不符合???錯在紅色字?


Private Declare Function MsgBoxTest Lib "user32" Alias "MessageBoxTimeoutA" ( _
    ByVal hwnd As Long, _
    ByVal lpText As String, _
    ByVal lpCaption As String, _
    ByVal wType As VbMsgBoxStyle, _
    ByVal wlange As Long, _
    ByVal dwTimeout As Long) As Long
Private Sub Worksheet_Calculate()
Application.DisplayStatusBar = False
  Dim sStr$
  Dim ZZ As Range
  
  sStr = ""
  sStr2 = ""
  For Each ZZ In Range("c2:c111")
    If Not IsError(ZZ) Then
      If Range("Q26").Value = 1 And flag = True Then
        M = Round(ZZ - ZZ.Offset(, 26), 2)
        If M >= ZZ.Offset(, 2) Then
          If sStr <> "" Then sStr = sStr & Chr(10)
          sStr = sStr & "" & Cells(ZZ.Row, 2).Value & "=====> " _
                 & Round(ZZ - ZZ.Offset(, 26), 2)
        
        End If
        If M <= -ZZ.Offset(, 2) Then
          If sStr2 <> "" Then sStr2 = sStr2 & Chr(10)
          sStr2 = sStr2 & "" & Cells(ZZ.Row, 2).Value & "=====> " _
                   & Round(ZZ - ZZ.Offset(, 26), 2)
         
        End If
      End If
    End If
  Next
  If sStr <> "" Then
    MsgBoxTest 0, "", "", sStr, 0, 2500
  End If
  If sStr2 <> "" Then
   MsgBoxTest 0, "", "", sStr2, 0, 2500
  End If

3.另外一個方法用" FindWindow " 來關閉這訊息窗,不過找不到這訊息窗? test.rar (9.63 KB)
http://hi.baidu.com/zzllrr/item/9a561a634853bc90c4d2493d

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

1綜上你可以試試 :
MsgBoxTest 0, sStr, "提示訊息", 0, 0, 2500.
luhpro 發表於 2013-8-22 23:56


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

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

本帖最後由 t8899 於 2013-8-27 06:11 編輯
1. 本來若你用的是 MsgBox 函數, 則在 MsgBox 函數 的說明中有寫到 :
語法
MsgBox(prompt[, buttons] [ ...
luhpro 發表於 2013-8-26 22:54


找到了  ====> vbSystemModal 應用程式強制回應:使用者必須先回應此訊息方塊,才能在目前的應用程式中繼續工作
沒加vbSystemModal,訊息視窗出現時,點其他軟體為active,excel的訊息視窗就無法在最前面
意即不知道有此訊息..
MsgBoxTest 0, sStr, "提示訊息",vbSystemModal, 0, 2500  ====>這是OK
MsgBoxTest 這個API (應該已包含MSGBOX的所有功能,不然vbSystemModal無法作用才對?)

VbMsgBoxSetForeground 65536 指定訊息方塊視窗作為前景視窗 ,應該也可以掛在vbSystemModal 同等位置
MsgBoxTest 0, sStr, "提示訊息",VbMsgBoxSetForeground , 0, 2500
測試了一下沒作用

TOP

        靜思自在 : 脾氣嘴巴不好,心地再好也不能算是好人。
返回列表 上一主題