1. #1

    Question about Button:Disable() and Button:Enable()

    Might be a dumb question, but i don't understand the correct usage for Buttonisable() and its counterpart in an addon.
    If i type
    Code:
    /run HonorFrameSoloQueueButton:Disable();
    ingame, it works and my solo bg join button gets greyed out.
    Now i want to write an addon (even if it may exist already) to grey out that button if i'm in a group.

    My code:
    Code:
    -- disables solo battlefield button in party 
    -- enables solo battlefield button if solo
    function disableOrEnableQueueButton()
      if (GetNumGroupMembers()==0) then
        DEFAULT_CHAT_FRAME:AddMessage("No group found check."); 
        HonorFrameSoloQueueButton:Enable();
      else
        DEFAULT_CHAT_FRAME:AddMessage("Group found check.");  
        HonorFrameSoloQueueButton:Disable();
      end
    end
    
    
    function groupChanged_OnEvent(_, ...)
      DEFAULT_CHAT_FRAME:AddMessage("Event triggered.");
      disableOrEnableQueueButton()
    end
    
    local frame = CreateFrame("Frame", "groupChanged");
    frame:SetScript("OnEvent", groupChanged_OnEvent);
    frame:RegisterEvent("GROUP_ROSTER_UPDATE");
    Those DEFAULT_CHAT_FRAME:AddMessage are only to test if the event is triggered and these are working correctly.
    Would be great if somebody could help me and explain why HonorFrameSoloQueueButton:Enable() in the addon doesn't work.
    (I'm just learning a bit addon-programming, so linking to working addons is not the point. I hope my english is good enough.)

  2. #2
    The HonorFrame is available when the addon Blizzard_PVPUI is loaded. You can check this with the event ADDON_LOADED.
    Or just check whether the HonorFrame exists or not before you try to do something with the button.
    Code:
    if HonorFrame then 
       some code
    end

    But it is most important to block other functions to enable the button again
    Code:
    --If you are in a group
    --Disable the button
    HonorFrameSoloQueueButton:Disable()
    --Prevent that the button will be reenabled
    HonorFrameSoloQueueButton.Enable = function() end
    
    
    --If you are solo again
    --Button:Enable() enables the button again
    HonorFrameSoloQueueButton.Enable = Enable
    --Enable the button
    HonorFrameSoloQueueButton:Enable()
    Hope this helps.

  3. #3
    Thanks Urtgard! I'll try it out when i have some time

  4. #4
    Code:
    if IsAddOnLoaded("Blizzard_PVPUI") then
        stuff
    end
    is another option

  5. #5
    And another thanks to modernist. I've used both of your tips and now it works
    I use both events (ADDON_LOADED and GROUP_ROSTER_UPDATE) to test if something could be changing.
    Then the function tests if the pvpui is loaded and enables/disables the button based on group-status.
    If something is inefficient, could be written better and you want to help me, any hints are appreciated!

    Code:
    -- disable/enable solo bg join button in group/solo
    function disableOrEnableQueueButton()
      if IsAddOnLoaded("Blizzard_PVPUI") then
        if (GetNumGroupMembers()==0) then
          HonorFrameSoloQueueButton.Enable = Enable
          HonorFrameSoloQueueButton:Enable();
        else 
          HonorFrameSoloQueueButton:Disable();
          HonorFrameSoloQueueButton.Enable = function() end
        end
      end
    end
    
    
    -- check solo bg button when group changes
    function groupChanged_OnEvent(_, ...)
      disableOrEnableQueueButton()
    end
    
    local frame = CreateFrame("Frame", "groupChanged");
    frame:SetScript("OnEvent", groupChanged_OnEvent);
    frame:RegisterEvent("GROUP_ROSTER_UPDATE");
    
    
    -- check solo bg button when pvp-frame loads 
    function pvpUILoaded_OnEvent(_, ...)
      if IsAddOnLoaded("Blizzard_PVPUI") then
        disableOrEnableQueueButton()
      end 
    end
    
    local frame = CreateFrame("Frame", "pvpUILoaded");
    frame:SetScript("OnEvent", pvpUILoaded_OnEvent);
    frame:RegisterEvent("ADDON_LOADED");
    Last edited by Merador; 2014-08-02 at 10:41 AM.

  6. #6
    Deleted
    Some things that should be mentioned:
    • You've got a global function with the extremely generic name disableOrEnableQueueButton. That's asking for a naming conflict.
      There's really no reason for that to be global, so I'd advise making it a local instead.
    • You're creating a new anonymous function to replace HonorFrameSoloQueueButton.Enable every time your events fire.
    • In your "reenable" logic, you're setting HonorFrameSoloQueueButton.Enable = Enable. "Enable" is not assigned anywhere in your code, so unless you're lucky and another addon is setting that global (which is A Bad Thing™ on its own), you're just setting it to nil (which should, really, be throwing an error on the line after that - are you sure you have Lua errors enabled?)
    • Your frames have generic names. While you only use the reference returned from CreateFrame anyway, so there's no conflicts in your code, it's still cluttering the global namespace (and might lead to conflicts for other addons that do use the global reference). As those frames aren't actually displayed anywhere, there's no real reason for them to have a name, either (frame names are, arguably, only useful for two things - to be displayed in /fstack, and to work with some (*shudder*) UI XML SecureTemplates that still use $parent in their name="" attribute).
    • You have two separate frames for your two events. While it doesn't make much of a difference in this case, it's still bad practice. The second argument passed to your event handler is the event name of the event that triggered - use it.
    • There's no reason to keep switching the enable function back and forth the way you do. What you (probably) want in your case is complete control over the HonorFrameSoloQueueButton's enabled state - so just take it.

    Here's a cleaned-up version:
    Code:
    local empty = function() end
    local loaded, enable, disable
    
    local function disableOrEnableQueueButton()
        if IsInGroup(LE_PARTY_CATEGORY_HOME) then
            disable(HonorFrameSoloQueueButton)
        else
            enable(HonorFrameSoloQueueButton)
        end
    end
    
    
    local function onEvent(self, event, name)
        if event == "ADDON_LOADED" then
            if name == "Blizzard_PVPUI" then
                loaded, enable, disable = true, HonorFrameSoloQueueButton.Enable, HonorFrameSoloQueueButton.Disable
                HonorFrameSoloQueueButton.Enable, HonorFrameSoloQueueButton.Disable = empty, empty
                self:UnregisterEvent("ADDON_LOADED") -- it'll only fire once, so no reason to keep it registered and taking up resources
                disableOrEnableQueueButton()
            end
        else
            if loaded then
                disableOrEnableQueueButton()
            end
        end
    end
    
    local frame = CreateFrame("Frame")
    frame:SetScript("OnEvent", onEvent)
    frame:RegisterEvent("GROUP_ROSTER_UPDATE")
    frame:RegisterEvent("ADDON_LOADED")

    Hope that helps. If you have any questions, feel free to ask.
    Last edited by mmocba105e19de; 2014-08-02 at 11:13 AM.

  7. #7
    Quote Originally Posted by Treeston View Post
    You've got a global function with the extremely generic name disableOrEnableQueueButton. That's asking for a naming conflict.
    There's really no reason for that to be global, so I'd advise making it a local instead.
    Bad mistake on my side, won't forget it in the future.
    Quote Originally Posted by Treeston View Post
    In your "reenable" logic, you're setting HonorFrameSoloQueueButton.Enable = Enable. "Enable" is not assigned anywhere in your code, so unless you're lucky and another addon is setting that global (which is A Bad Thing™ on its own), you're just setting it to nil (which should, really, be throwing an error on the line after that - are you sure you have Lua errors enabled?)
    I've lua errors enabled, but didn't get any. I must have been "lucky" on this one.
    Quote Originally Posted by Treeston View Post
    Your frames have generic names. While you only use the reference returned from CreateFrame anyway, so there's no conflicts in your code, it's still cluttering the global namespace (and might lead to conflicts for other addons that do use the global reference). As those frames aren't actually displayed anywhere, there's no real reason for them to have a name, either (frame names are, arguably, only useful for two things - to be displayed in /fstack, and to work with some (*shudder*) UI XML SecureTemplates that still use $parent in their name="" attribute).
    Didn't know you could create a frame without choosing a name...
    Quote Originally Posted by Treeston View Post
    You have two separate frames for your two events. While it doesn't make much of a difference in this case, it's still bad practice. The second argument passed to your event handler is the event name of the event that triggered - use it.
    ... as I didn't know that you could register more than one event to a frame. Good to know!
    Quote Originally Posted by Treeston View Post
    There's no reason to keep switching the enable function back and forth the way you do. What you (probably) want in your case is complete control over the HonorFrameSoloQueueButton's enabled state - so just take it.
    Tiny question here.
    Have i understood it right, that you save the function "HonorFrameSoloQueueButton.Enable" in the variable "enable" and afterwards set the function "HonorFrameSoloQueueButton.Enable" to an empty function.
    => Nothing can use the original function "HonorFrameSoloQueueButton.Enable", but my addon can use it as "enable".
    Therefore i have complete controll over this function. (same for disable)

  8. #8
    Deleted
    Quote Originally Posted by Merador View Post
    Tiny question here.
    Have i understood it right, that you save the function "HonorFrameSoloQueueButton.Enable" in the variable "enable" and afterwards set the function "HonorFrameSoloQueueButton.Enable" to an empty function.
    => Nothing can use the original function "HonorFrameSoloQueueButton.Enable", but my addon can use it as "enable".
    Therefore i have complete controll over this function. (same for disable)
    Correct. Any addon calling HonorFrameSoloQueueButton:Enable() (or :Disable()) will be calling the empty function (and thus do nothing). The reference to the original function is stored in the file-scope local enable (or disable respectively) so you can still access it using enable(HonorFrameSoloQueueButton) - note that you can no longer do a method-style call (using a colon) as it's no longer accessed as a table member, so you need to pass the table as the first argument (which the colon syntax does automatically - table:method() does exactly the same as table.method(table)).

    PS: You don't really have "full control" in the sense that yes, one could circumvent it pretty easily if one actually wanted to. For example, all frames of a given type use the same metatable where the default implementations of all the functions are stored, so simply doing CreateFrame("Button").Enable(HonorFrameSoloQueueButton) (or, more efficiently, getmetatable(HonorFrameSoloQueueButton).__index.Enable(HonorFrameSoloQueueButton)) would circumvent the empty-function block - but if someone implements that, they (hopefully) have a good reason to do so.
    Last edited by mmocba105e19de; 2014-08-02 at 12:36 PM.

  9. #9
    Ok, thanks for your help Treeston.
    I'll remember those tips and use them in other addons!

  10. #10
    Quote Originally Posted by Treeston View Post
    Some things that should be mentioned:
    In your "reenable" logic, you're setting HonorFrameSoloQueueButton.Enable = Enable. "Enable" is not assigned anywhere in your code, so unless you're lucky and another addon is setting that global (which is A Bad Thing™ on its own), you're just setting it to nil (which should, really, be throwing an error on the line after that - are you sure you have Lua errors enabled?)
    Yeah, this is on thing I don't realy understand.
    If you disable all addons and just use these 2 macros, it works.
    But if you check what Enable is, it is nil.

    Code:
    /run HonorFrameSoloQueueButton:Disable(); HonorFrameSoloQueueButton.Enable = function() end
    
    /run HonorFrameSoloQueueButton.Enable = Enable; HonorFrameSoloQueueButton:Enable()

  11. #11
    Deleted
    I derped a bit myself on that one.

    The baseline :Enable() is taken from the metatable's __index precisely because an .Enable doesn't exist in the frame table by default. If you set it to nil, all you're doing is making it use the .Enable in the __index again.

    In other words:
    Code:
    /run HonorFrameSoloQueueButton.Enable = nil print(HonorFrameSoloQueueButton.Enable == getmetatable(HonorFrameSoloQueueButton).__index.Enable)
    will give you true, while
    Code:
    /run print(rawget(HonorFrameSoloQueueButton,"Enable"))
    will give you nil

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •