WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   AddOn Help/Support (https://www.wowinterface.com/forums/forumdisplay.php?f=3)
-   -   Overwriting text (https://www.wowinterface.com/forums/showthread.php?t=49918)

benots4 09-17-14 05:03 PM

Overwriting text
 
I am making something like a scroll frame, a frame containing several rows of frames that I want to write text in and then scroll through. I can do that fine only each update writes the new text over the top of the old text, making it unreadable. Addons like Auctioneer do this all the time so I must be missing something.

Creating the subframes and text looks like this
Code:

function GGCreatePDField(Name, Parent, Point, ofsx , ofsy, fwidth, fheight, text)
        local f = CreateFrame("Frame", Name, Parent)                               
        f:SetPoint(Point, ofsx,ofsy )
        f:SetWidth(fwidth)
        f:SetHeight(fheight)
        f.text = f:CreateFontString("$parentName", "OVERLAY")
        f.text:SetTextColor(1, 1, 1, 1)
        f.text:ClearAllPoints()
        f.text:SetPoint("LEFT", f, "LEFT")
        f.text:SetJustifyH("LEFT")
        f.text:SetJustifyV("TOP")
        f.text:SetFont(STANDARD_TEXT_FONT, 12, "OUTLINE")
        f.text:SetText(text)
        return f.text
        end

The display loop looks like this

Code:

        for i = 1, displayRows  do
                charLevel = GGCreatePDField("Level", GroupMemberList, "TOPLEFT", 6,-ofsy , 40, 16,nil)
                charLevel:SetText(pInfoArray[v].Level)
                ofsy = ofsy + displayRowHeight
                i=i + 1
                v = v + 1
        end


Phanx 09-17-14 07:10 PM

1) You're creating a new font string every time, instead of reusing the old one. Keep track of the already-created rows and only create a new one if you're already using all the existing ones.

2) Your update loop doesn't need to manually increment i -- the whole purpose of a for loop is to do that for you.

3) You're creating multiple objects with the global names "Level" and "LevelName", which is bad for many reasons. These objects don't need names at all, these names are extremely generic and extremely likely to conflict with other addons or the default UI, and since they're all the same they're even conflicting with each other. You also appear to be setting many other generically named variables like "charLevel" and "ofsy" in the global namespace, which is called leaking and is bad. Put "local" keywords in front of each variable you declare, unless it absolutely needs to be global.

I'd suggest something more like this:

Code:

local rowFrames = {}

local function CreateRow(i)
        local f = CreateFrame("Button", nil, parent) -- Doesn't need a global name.
        f:SetWidth(40)
        f:SetHeight(16)
        if i == 1 then
                f:SetPoint("TOPLEFT", parent, 6, -6)
        else
                f:SetPoint("TOPLEFT", rowFrames[i-1], "BOTTOMLEFT")
        end

        local text = f:CreateFontString(nil, "OVERLAY") -- Doesn't need a global name.
        text:SetPoint("LEFT")
        text:SetPoint("RIGHT")
        text:SetJustifyH("LEFT")
        text:SetFont(STANDARD_TEXT_FONT, 12, "OUTLINE")
        text:SetTextColor(1, 1, 1, 1)
        f:SetFontString(text) -- This is why it's a Button instead of a plain Frame,
                -- so you can now :SetText on the Button itself.

        f:SetID(i)
        rowFrames[i] = f
        return f
end

for i = 1, NUM_ROWS_TO_DISPLAY do
        local row = rowFrames[i] or CreateRow(i)
        row:SetText(YOUR_TEXT_HERE)
end

-- Hide any unused rows:
for i = NUM_ROWS_TO_DISPLAY + 1, #rowFrames do
        rowFrames[i]:SetText(nil)
end


benots4 09-18-14 06:42 AM

I know the code I posted is whacked, I have been trying a lot of different things, local, named, not named, buttons, frames, creating new, reusing. Just about to delete the whole mess and say it can't be done.

looks like this is what I have been missing

f:SetID(i)
rowFrames[i] = f

benots4 09-18-14 06:41 PM

That didn't work either. In the function below v is set by the scroll bar. Here are screen shots.
After init before scrolling:
Post Scroll :

code:
Code:

function ShowGroupMemberList(v)
        local MLheight = 210
        local MLWidth = 355
        local MLyoffset = - tt:GetHeight() -10  -- offset from the bottom of the main frame
        local showOffline = (GetGuildRosterShowOffline() and true or false);
        local pInfoArray = GetGuildMemberList(showOffline);
        local GroupMemberList = GGCreateFrame(LT3GuildRoster, "MemberList", "TOPLEFT", 0, MLyoffset, MLWidth, MLheight, LT3GuildRoster);
        GroupMemberList:Show();

        local displayRows = 14
        local displayRowHeight = 16
        local ofsx = 110
        local ofsy = 0       
        local rowFrames = {}
       
        local function CreateRow(i)
                local f = CreateFrame("Button", nil, GroupMemberList) -- Doesn't need a global name.
                f:SetWidth(300)
                f:SetHeight(16)
                if i == 1 then
                        f:SetPoint("TOPLEFT", GroupMemberList, ofsx, -ofsy)
                else
                        f:SetPoint("TOPLEFT", rowFrames[i-1], "BOTTOMLEFT")
                end
                local text = f:CreateFontString(nil, "OVERLAY") -- Doesn't need a global name.
                text:SetPoint("LEFT")
                text:SetPoint("RIGHT")
                text:SetJustifyH("LEFT")
                text:SetFont(STANDARD_TEXT_FONT, 12, "OUTLINE")
                text:SetTextColor(1, 1, 1, 1)
                f:SetFontString(text) -- This is why it's a Button instead of a plain Frame,
                -- so you can now :SetText on the Button itself.
                f:SetID(i)
                rowFrames[i] = f
                return f
        end

        if v < 1 then v = 1 end
        for i = 1, displayRows  do
                local name = pInfoArray[v].Name;
                if pInfoArray[v].Class and pInfoArray[v].Class:upper() ~= "UNKNOWN" then
                        name = "\124cFF"..(pInfoArray[v].Online and GuildRole_Class_Colors[pInfoArray[v].Class:upper()] or "808080")..pInfoArray[v].Name.."\124r";
                end               
                local row = rowFrames[i] or CreateRow(i,rowFrames ,ofsx, ofsy)
                row:SetText(name)
                v=v+1
        end
       
end


Phanx 09-18-14 09:46 PM

Your caching table and the CreateRow function need to be defined outside of the update function -- otherwise, every time you call the update function, you're creating a new list of rows instead of using the old one, which defeats the purpose of keeping a list of already-created rows in the first place.

Also, your CreateRow function cannot refer to variables that are inside the update function. If you already know you want the first row to be 100px from the left and 0px from the top, just hardcode 110 and 0 as the position offsets. Since each additional row is anchored relative to the previous row, instead of all rows being anchored relative to the parent frame, there's no need to keep track of the y offset or change any positions in the update function.

Similarly, you only need to pass the row number to the CreateRow function -- you don't need to pass a reference to the list of created frames, and you don't need to pass any position offsets.

The :SetID() call doesn't really matter as far as reusing rows go, but it does mean that if you have a reference to the row frame, you can call :GetID() to find out [b]which[/i] row it is.

benots4 09-19-14 06:40 AM

Thanks for your help. I put your function as a separate function, same result, broke into 3 functions same affect, and then decided to put it all in one exactly as you suggested, same effect. Believe me I have coding this for a week and I feel I have already done what you suggest. I have made a slash command for a Field1:SetText("Change") and I get the same thing. I put the entire first pass in the init script then only called a function that had nothing but set text statements, same thing. I don't think hard coding the columns is the answer as you see I have at least 7 other columns to fill in, provided there is a way to actually change the text. I have at least 112 cells to set, which I could hard code and would if it provided a different outcome, but I think I tried that. What you’re telling me is that there is no way to change the text; I can only use the set text function to write text over the existing text. Don’t suggest SetText(nil) cause that does nothing. Frustrated I am.

semlar 09-19-14 09:14 AM

Quote:

Originally Posted by benots4 (Post 296966)
What you’re telling me is that there is no way to change the text; I can only use the set text function to write text over the existing text.

No, phanx is telling you to stop creating new font strings on top of the old ones every time you want to update the text.

She gave you an example and you put the entire thing inside of a function which is overwriting the table that's tracking what rows have already been created every time it's run.

Every time you call "ShowGroupMemberList", which I'm guessing is being called every time you scroll, you're wiping out the table that's supposed to be tracking which rows have already been created.

The ONLY part that should be inside of that function is this:
Lua Code:
  1. function ShowGroupMemberList(v)
  2.     if v < 1 then v = 1 end
  3.     for i = 1, displayRows  do
  4.         local name = pInfoArray[v].Name;
  5.         if pInfoArray[v].Class and pInfoArray[v].Class:upper() ~= "UNKNOWN" then
  6.             name = "\124cFF"..(pInfoArray[v].Online and GuildRole_Class_Colors[pInfoArray[v].Class:upper()] or "808080")..pInfoArray[v].Name.."\124r";
  7.         end    
  8.         local row = rowFrames[i] or CreateRow(i)
  9.         row:SetText(name)
  10.         v=v+1
  11.     end
  12. end
Everything else that you put in that function should be outside of, and above it.

benots4 09-19-14 07:18 PM

Just so you know I figured it out, or at least a work around. If you run into this again do not set text when the button/fontstring is created, don't even put a SetText(text). Only set text in the update function

rowFrames[i]:SetText(text) = Good
CreateRow[i]:SetText(text) = BAD if you plan on changing later

Thanks for your help and guidance.

Phanx 09-19-14 09:47 PM

Quote:

Originally Posted by benots4 (Post 297007)
Just so you know I figured it out, or at least a work around.

I'm not sure what there is to figure out. The code I gave you works. You're breaking it by wrapping it in functions and adding extra things that don't need to be there. Just use the code I gave you.

Quote:

Originally Posted by benots4 (Post 297007)
rowFrames[i]:SetText(text) = Good
CreateRow[i]:SetText(text) = BAD if you plan on changing later

#1 is also bad, because it will fail if you need more rows than you already created.

SDPhantom 09-20-14 04:00 AM

If you're not using the buttons for anything other than to display text, why not just create the FontStrings directly on the roster frame?


All times are GMT -6. The time now is 09:31 AM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI