Quantcast
Overwriting text - WoWInterface
Thread Tools Display Modes
09-17-14, 05:03 PM   #1
benots4
A Fallenroot Satyr
AddOn Author - Click to view addons
Join Date: Aug 2009
Posts: 20
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
  Reply With Quote
09-17-14, 07:10 PM   #2
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
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
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Donít message me about addon bugs or programming questions.
  Reply With Quote
09-18-14, 06:42 AM   #3
benots4
A Fallenroot Satyr
AddOn Author - Click to view addons
Join Date: Aug 2009
Posts: 20
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
  Reply With Quote
09-18-14, 06:41 PM   #4
benots4
A Fallenroot Satyr
AddOn Author - Click to view addons
Join Date: Aug 2009
Posts: 20
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
  Reply With Quote
09-18-14, 09:46 PM   #5
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
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.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Donít message me about addon bugs or programming questions.

Last edited by Phanx : 09-18-14 at 09:49 PM.
  Reply With Quote
09-19-14, 06:40 AM   #6
benots4
A Fallenroot Satyr
AddOn Author - Click to view addons
Join Date: Aug 2009
Posts: 20
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.
  Reply With Quote
09-19-14, 09:14 AM   #7
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,059
Originally Posted by benots4 View Post
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.
  Reply With Quote
09-19-14, 07:18 PM   #8
benots4
A Fallenroot Satyr
AddOn Author - Click to view addons
Join Date: Aug 2009
Posts: 20
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.
  Reply With Quote
09-19-14, 09:47 PM   #9
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by benots4 View Post
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.

Originally Posted by benots4 View Post
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.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Donít message me about addon bugs or programming questions.
  Reply With Quote
09-20-14, 04:00 AM   #10
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,005
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?
__________________
ESOUI AddOns | WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote

WoWInterface » AddOns, Compilations, Macros » AddOn Help/Support » Overwriting text

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off