Making Excel-funksjoner påvirke 'andre' celler

stemmer
4

La oss si at jeg oppretter en Sub (ikke en funksjon) som har som oppgave i livet er å ta den aktive cellen (dvs. Utvalg) og sette en tilstøtende celle til en viss verdi. Dette fungerer fint.

Når du prøver å konvertere Sub til en funksjon og prøver å vurdere det fra fra regneark (dvs. å sette det er formelen til = MyFunction ()) Excel vil bjeffe på det faktum at du prøver å påvirke verdien av den ikke-aktive celle, og ganske enkelt tvinge funksjon å returnere #VALUE uten å berøre de tilstøtende celle.

Er det mulig å slå av denne beskyttende atferd? Hvis ikke, hva er en god måte å komme seg rundt det? Jeg leter etter noe en kompetent utvikler kunne utrette over en 1-2 ukers periode, hvis det er mulig.

Hilsen, Alan.

Merk: Jeg bruker 2002, så jeg ville favorisere en løsning som ville fungere for den versjonen. Når det er sagt, hvis fremtidige versjoner gjør denne betydelig enklere, vil jeg gjerne vite om det også.

Publisert på 14/10/2008 klokken 11:58
kilden bruker
På andre språk...                            


6 svar

stemmer
2

Jeg bruker Excel 2007, og det fungerer ikke. Excel nevner det skaper en sirkelreferanse. Jeg tror ikke du kan endre andre celler fra en funksjon, bare returnere en verdi.

Det er en slags funksjonell programmering, ingen bivirkninger. Hvis du bare kan endre andre celler inne i en funksjon (brukes fra et regneark), så det er ingen måte for Excel å vite for og hva du skal beregne om en celleforandringer.

Denne artikkelen inneholder også mye informasjon om hvordan Excel gjør omberegning. Men det sier ikke at de andre cellene er frosset.

Jeg vet ikke hva du prøver å gjøre, men hvorfor ikke bare plassere en annen funksjon i den tilstøtende cellen, som tar den første cellen som en parameter?

Eksempel:

Public Function Bar(r As Range) As Integer
  If r.Value = 2 Then
    Bar = 0
  Else
    Bar = 128
  End If
End Function
Svarte 14/10/2008 kl. 13:05
kilden bruker

stemmer
2

Ifølge Hvordan lage Custom brukerdefinerte Excel funksjoner :

Begrensninger av UDF sin

  • Kan ikke plassere en verdi i en annen enn den celle (eller område) celle inneholder formelen. Med andre ord, er UDF er ment å brukes som "formler", ikke nødvendigvis "makroer".

Så ser det ut som det ikke kan gjøres.

Svarte 14/10/2008 kl. 14:09
kilden bruker

stemmer
9

Det kan ikke gjøres, som er fornuftig fordi:

  • Når et regneark funksjonen kalles, er cellen som inneholder funksjon ikke nødvendigvis den aktive celle. Så du ikke finner den tilstøtende cellen pålitelig.

  • Når Excel rekalkulerer et regneark, må den opprettholde avhengigheter mellom cellene. Så det kan ikke tillate regnearkfunksjoner å vilkårlig endre andre celler.

Det beste du kan gjøre er en av:

  • Håndter SheetChange hendelsen. Hvis en celle som inneholder en funksjon er å endre, modifisere den tilstøtende cellen.

  • Sett en regnearkfunksjon i den tilstøtende cellen for å returnere verdien du ønsker.

Oppdater

Når det gjelder kommentaren: "Jeg vil gjerne at denne funksjonen skal fungere på en 'blank' regneark, så jeg kan egentlig ikke stole på endre tilfelle av regneark som kan ennå ikke eksisterer, men må ringe denne funksjonen":

  • Kan du sette din funksjon i en XLA add-in? Så din XLA-tillegget kan håndtere Application SheetChange (*) hendelse for alle arbeidsbøker som åpnes i at forekomst av Excel?

Når det gjelder kommentaren: "Likevel, hvis du holder Excel på CalculationMode = xlManual og fylle på bare verdier, bør du være helt fint"

  • Selv når CalculationMode er xlManual trenger Excel for å opprettholde et avhengighetsforhold av referanser mellom cellene slik at det kan regne i riktig rekkefølge. Og hvis en av funksjonene kan oppdatere en vilkårlig celle, vil dette rotet opp rekkefølgen. Som er antagelig grunnen til at Excel pålegger denne begrensningen.

(*) Jeg opprinnelig skrev endre ovenfor, korrigert nå - selvfølgelig riktig arrangementet er SheetChange for arbeidsbok eller Application objekter, eller Endre for regnearkobjekt.

Oppdater 2 Noen bemerkninger om AlanR innlegg som beskriver hvordan du 'litt' gjøre det arbeidet du bruker en timer:

  • Det er ikke klart hvordan timerfunksjon ( "Woohoo") vil vite hvilke celler for å oppdatere. Man har ingen informasjon som indikerer hvilken celle inneholder formelen som utløste tidsuret.

  • Dersom formelen eksisterer i mer enn én celle (i samme eller forskjellige arbeidsbøker), deretter UDF vil bli kalt flere ganger i løpet av en ny beregning, å overskrive timerId. Som et resultat, vil du klarer å ødelegge timeren pålitelig, og vil lekke Windows-ressurser.

Svarte 14/10/2008 kl. 14:42
kilden bruker

stemmer
1

Takk alle for å svare. Det er mulig å gjøre dette! På en måte. Jeg sier 'litt' fordi teknisk sett den 'funksjonen' ikke påvirker cellene rundt det. Praktisk talt, men kan noen fortelle forskjellen.

Trikset er å bruke en Win32 API for å starte en timer, og så snart den går av deg gjøre hva du vil til hva cellen og slå av timeren.

Nå er jeg ikke ekspert på hvordan COM threading arbeid (selv om jeg vet VBA er Single Leilighet gjenger), men vær forsiktig om Timer kjører bort med Excel prosess og krasje den. Dette er egentlig ikke noe jeg ville foreslå som en løsning på alle andre regneark.

Bare lage en modul med dette innholdet:

Option Explicit

Declare Function SetTimer Lib "user32" (ByVal HWnd As Long, _
  ByVal IDEvent As Long, ByVal mSec As Long, _
  ByVal CallFunc As Long) As Long

Declare Function KillTimer Lib "user32" (ByVal HWnd As Long, _
  ByVal timerId As Long) As Long

Private timerId As Long

Private wb As Workbook
Private rangeName As String
Private blnFinished As Boolean

Public Sub RunTimer()

    timerId = SetTimer(0, 0, 10, AddressOf Woohoo)


End Sub


Public Sub Woohoo()

    Dim i As Integer

'    For i = 0 To ThisWorkbook.Names.Count - 1
'        ThisWorkbook.Names(i).Delete
'    Next

     ThisWorkbook.Worksheets("Sheet1").Range("D8").Value = "Woohoo"

     KillTimer 0, timerId

End Sub
Svarte 16/10/2008 kl. 11:37
kilden bruker

stemmer
1

Selv om du ikke kan gjøre dette i Excel, er det mulig i resolverkort One (selv om det er fortsatt en ganske merkelig ting å gjøre).

Det er et regneark som lar deg definere tilpassede funksjoner i Python som du deretter kan ringe fra en celle formel i nettet.

Som et eksempel på hva du spør, kan det være lurt å definere en safeDividefunksjon som (i stedet for å oppdra en ZeroDivisionError) fortalte om problemet ved farging nevner celle, og setter en feilmelding ved siden av. Du kan definere det slik:

def safeDivide(numerator, cellRange):
    if not isinstance(cellRange, CellRange):
        raise ValueError('denominator must be a cell range')
    denominator = cellRange.Value
    if denominator == 0:
        cell = cellRange.TopLeft
        cell.BackColor = Color.Red
        cell.Offset(1, 0).Value = 'Tried to divide by zero'
        return 0
    return numerator / denominator

Det er en ekstra rynke: funksjoner som blir vedtatt celler bare bli passert celleverdien, så for å omgå at vi insisterer på å bli vedtatt en en-celle Celle for nevneren.

Hvis du prøver å gjøre uvanlige ting med regneark som ikke helt passer inn i Excel, eller du er interessert i å bruke kraften i Python å jobbe med dine regnearkdata, er det verdt å ta en titt på Resolver One.

Svarte 27/11/2008 kl. 15:07
kilden bruker

stemmer
1

Her er en enkel VBA løsning som fungerer. For dette eksempelet, åpne en ny Excel-arbeidsbok og kopiere følgende kode inn koden område for Sheet1(ikke ThisWorkbookeller VBA Module). Så gå inn Sheet1og sette noe inn i en av de øvre venstre cellene i regnearket. Hvis du skriver inn et tall og trykk Enter, deretter cellen til høyre vil bli oppdatert med 4 ganger så mange, og cellen bakgrunnen blir lyseblå. Enhver annen verdi fører til den neste cellen til å bli slettet. Her er koden:

Dim busy As Boolean
Private Sub Worksheet_Change(ByVal Target As Range)
  If busy Then Exit Sub
  busy = True
  If Target.Row <= 10 And Target.Column <= 10 Then
    With Target.Offset(0, 1)
      If IsNumeric(Target) Then
        .Value = Target * 4
        .Interior.Color = RGB(212, 212, 255)
      Else
        .Value = Empty
        .Interior.ColorIndex = xlColorIndexNone
      End If
    End With
  End If
  busy = False
End Sub

Subrutinen fanger opp alle celle endre hendelser i arket. Dersom raden og kolonnen er begge <= 10, da cellen til høyre er satt til 4 ganger den endrede celle hvis verdien er numerisk; ellers cellen til høyre er fjernet.

Svarte 06/01/2009 kl. 20:51
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more