Freeing Allocated Objects for a Class
Author |
Message |
Cervantes
|
Posted: Thu Jun 02, 2005 5:36 pm Post subject: Freeing Allocated Objects for a Class |
|
|
So I've got my button class going on overload. Buttons everywhere (313 at the maximum [in case you're wondering, 300 of them represent seats]). Each button has a font that it uses to draw the label on top of itself.
Sometimes, my program will crash, saying that "Font was never allocated". Okay, it definately was. I allocate the font in my INIT procedure and use it in a few other procedures, but only AFTER I've called the INIT procedure. This I am sure of.
The thing is, I don't EVER free the fonts. I free the instances of the button class at the end of my program, but I don't have a Font.Free procedure or line in my class. (Freeing the instance of the class doesn't free the fonts, does it?) I suspect this is the problem.
If so, how would I impliment a freeing of the fonts? Right now the best idea I have is making a procedure to free the font and call that procedure for every button I have just before I free the instances of the button class. This would not be all that pretty, however. I'm wondering if anyone has any better ideas.
Also, what are Turing's limitations in terms of fonts? With pictures, you can't have more than 1000 active at any time. I tried a basic program that ran through a for loop and created 12500 fonts, and it did not crash, though it got really really slow. What are the ways a program can overdo it with the fonts, and crash because of it?
Thanks! |
|
|
|
|
|
Sponsor Sponsor
|
|
|
Delos
|
Posted: Thu Jun 02, 2005 9:11 pm Post subject: (No subject) |
|
|
So, what you're saying is that for ButtonA, you have a font stream fontA, and for ButtonB...etc etc.
Is that it? That seems a little excessive to me, since you could just use the same font stream for all, but set your parameters up to handle the text.
This seems self-evident, so I doubt that this is the case - I have a little more faith than that in you...
I've never seen that particular error before, having rarely dabbled with Fonts myself. Just set up an error catching routine that you can call after each procedure call (something that checks for Error.Last, and possible pauses the programme, opens a new window, and displays a message).
It could help with the debugging. Of course, figuring out where to put it would be fun...
If only Turing could have some sort of implicit call that gets associated with every procedure.
Have fun, and it wouldn't hurt to show us a little code to...expidite the proceedings. |
|
|
|
|
|
Cervantes
|
Posted: Thu Jun 02, 2005 10:03 pm Post subject: (No subject) |
|
|
Thanks for the reply, Delos.
Delos wrote:
So, what you're saying is that for ButtonA, you have a font stream fontA, and for ButtonB...etc etc.
Is that it? That seems a little excessive to me, since you could just use the same font stream for all, but set your parameters up to handle the text.
Yes, each button has its own fonts. In the INIT procedure, a few of the parameters determine the font, fontheight, and font colour. I could have several buttons in several different programs that have different fonts and colours. I did not want to make this class like Turing's built-in GUI; I wanted mine to be easily customizable.
If I were to have the same font stream for all buttons, it would mean giving the program(me) that accesses the class much more access to the way the buttons operate. It would also mean forcing them all to have the same font. Lastly, it would mean more coding.
Delos wrote:
I've never seen that particular error before, having rarely dabbled with Fonts myself.
Yeah, it seems to be a rare error, and so far it seems very difficult to understand. What's more frustrating is that after some tinkering I managed to get the error "Unknown Error Message", and yet I managed to figure that one out!
As for source, I don't think it will help, but here it is. You probably won't get the error though, as it does not occur that often and I've not narrowed down when it occurs. Also, you can see I've got some commented lines of Font.Free's and Font.New's, wrapped around wherever I need to use a font. This seems to work perfectly, though when I've got 300 buttons on one screen the Font.Free's and Font.New's make things get rather slow.
Turing: |
/*
Geoff Stanley
Created: March 2005
This class allows the creation of multiple, customizable buttons.
****************NOTES*******************
To create multiple buttons in a program, create an array of instances of this class. For example, to create 6 buttons:
var buttons : array 1 .. 6 of ^BUTTON
for i : 1 .. upper (buttons)
new BUTTON, buttons (i)
end for
then, use the INIT procedure to each button. If you don't want the button to be shown right away, hide it immediately after INITing it.
*/
class BUTTON
import Mouse %were this a unit (as it normally is. I just made it like this to avoid the bother of saving files to see an example) this import line would not be needed
export INIT, changeLabel, setActivity, setColour, move, show, hide, visible, clicked, draw
var button :
record
x1, y1, x2, y2 : int
xPadding, yPadding : int
active : boolean
show : boolean
pressed : boolean %if the mouse is over it and the button is held down
released : boolean %if the mouse is over it and the button is held down then released
boarder : %the boarder of the button
record
width, height : int %default: 1 (pixel)
clr :
record
top_left : int %default: white when not pressed, black when pressed
bottom_right : int %default: black when not pressed, white when pressed
end record
end record
label_ : %the text that appears on the button
record
text : string
font, fontHeight : int
fontName : string
x, y : int %will default so the text appears in the middle of the button
xDraw, yDraw : int %used to draw the label. Changes if the button is clicked.
clr : int
end record
clr : %the colour of the button
record
current : int %
main, highlight, select : int
end record
end record
/*initialize the button.
x1, y1, x2, y2 --> the coordinates of the bottom left and top right corners of the button
Alternatively, if x2 = 0, then x1 becomes the centre of the button. The width is determined by the fontsize, the font, the text, and the xPadding.
Similarly, if y2 = 0, then y1 becomes the centre of the button. The height is determined by the fontsize and the yPadding.
xPadding, yPadding --> if 0 is used for width and height, xPadding and yPadding are responsible for the number of pixels from the
edge of the button to the text
labelText --> the text that will appear in the button
fontName --> the name of the font. eg. "Times New Roman"
fontHeight --> the size (height, in pixels) of the font. eg. 12
labelClr --> the colour number for the text
mainClr --> the colour number of the button when it is not pressed or highlighted
highlightClr --> the colournumber of the button when the mouse is over it
selectClr --> the colour number of the button when it has been released
*/
proc INIT (x1, y1, x2, y2 : int, xPadding, yPadding : int, labelText : string, fontName : string, fontHeight : int,
labelClr : int, mainClr, highlightClr, selectClr : int)
button.label_.font := Font.New (fontName + ":" + intstr (fontHeight ))
button.label_.fontName := fontName
button.label_.fontHeight := fontHeight
%------------
if x2 = 0 then
button.x1 := round (x1 - Font.Width (labelText, button.label_.font ) / 2 - xPadding )
button.x2 := round (x1 + Font.Width (labelText, button.label_.font ) / 2 + xPadding )
else
button.x1 := x1
button.x2 := x2
end if
if y2 = 0 then
button.y1 := round (y1 - fontHeight / 2 - yPadding )
button.y2 := round (y1 + fontHeight / 1. 5 + yPadding ) %fontHeight / 1.5 (not / 2) because of hanging letters like "g"
else
button.y1 := y1
button.y2 := y2
end if
button.xPadding := xPadding
button.yPadding := yPadding
%-------------
button.active := true
button.show := true
button.pressed := false
button.released := false
%-------------
button.boarder.width := 1
button.boarder.height := 1
button.boarder.clr.top_left := white
button.boarder.clr.bottom_right := black
%-------------
button.label_.text := labelText
button.label_.x := round ((button.x1 + button.x2 ) / 2 - Font.Width (labelText, button.label_.font ) / 2)
button.label_.y := round ((button.y1 + button.y2 ) / 2 - fontHeight / 2)
button.label_.xDraw := button.label_.x
button.label_.yDraw := button.label_.y
button.label_.clr := labelClr
%-------------
button.clr.current := mainClr
button.clr.main := mainClr
button.clr.highlight := highlightClr
button.clr.select := selectClr
%Font.Free (button.label_.font)
end INIT
proc changeLabel (newLabel, fontName : string, fontHeight : int)
button.label_.text := newLabel
button.label_.fontName := fontName
button.label_.fontHeight := fontHeight
%button.label_.font := Font.New (fontName + ":" + intstr (fontHeight))
button.label_.x := round ((button.x1 + button.x2 ) / 2 - Font.Width (newLabel, button.label_.font ) / 2)
%Font.Free (button.label_.font)
end changeLabel
proc setActivity (active : boolean)
button.active := active
end setActivity
proc setColour (mainClr, highlightClr, selectClr : int)
button.clr.current := mainClr
button.clr.main := mainClr
button.clr.highlight := highlightClr
button.clr.select := selectClr
end setColour
proc move (newX1, newY1, newX2, newY2 : int)
%button.label_.font := Font.New (button.label_.fontName + ":" + intstr (button.label_.fontHeight))
if newX2 = 0 then
button.x1 := round (newX1 - Font.Width (button.label_.text, button.label_.font ) / 2 - button.xPadding )
button.x2 := round (newX1 + Font.Width (button.label_.text, button.label_.font ) / 2 + button.xPadding )
else
button.x1 := newX1
button.x2 := newX2
end if
if newY2 = 0 then
button.y1 := round (newY1 - button.label_.fontHeight / 2 - button.yPadding )
button.y2 := round (newY1 + button.label_.fontHeight / 1. 5 + button.yPadding ) %fontHeight / 1.5 (not / 2) because of hanging letters like "g"
else
button.y1 := newY1
button.y2 := newY2
end if
button.label_.x := round ((button.x1 + button.x2 ) / 2 - Font.Width (button.label_.text, button.label_.font ) / 2)
button.label_.y := round ((button.y1 + button.y2 ) / 2 - button.label_.fontHeight / 2)
button.label_.xDraw := button.label_.x
button.label_.yDraw := button.label_.y
%Font.Free (button.label_.font)
end move
%draws the button
proc draw
if button.show then
Draw.FillBox (button.x1, button.y1, button.x2, button.y2, button.clr.current )
%button.label_.font := Font.New (button.label_.fontName + ":" + intstr (button.label_.fontHeight))
Font.Draw (button.label_.text, button.label_.xDraw, button.label_.yDraw, button.label_.font, button.label_.clr )
%Font.Free (button.label_.font)
for w : 1 .. button.boarder.width
Draw.Line (button.x1 - w, button.y1, button.x1 - w, button.y2, button.boarder.clr.top_left )
Draw.Line (button.x2 + w, button.y1, button.x2 + w, button.y2, button.boarder.clr.bottom_right )
end for
for h : 1 .. button.boarder.height
Draw.Line (button.x1, button.y2 + h, button.x2, button.y2 + h, button.boarder.clr.top_left )
Draw.Line (button.x1, button.y1 - h, button.x2, button.y1 - h, button.boarder.clr.bottom_right )
end for
end if
end draw
% This function accomplishes two tasks. First, it sets the appropraite colour for the button.
% Second, it returns true if the button is released, false if it is not.
fcn clicked : boolean %make sure released is called before check in the loop. Reason: button.pressed
var x, y, btn : int %mouse
if button.show & button.active then
Mouse.Where (x, y, btn )
if x >= button.x1 and x <= button.x2 and y >= button.y1 and y <= button.y2 then
if btn ~ = 0 then
button.pressed := true %it's pressed if the button is down
button.clr.current := button.clr.select
button.boarder.clr.top_left := black
button.boarder.clr.bottom_right := white
button.label_.xDraw := button.label_.x + 1
button.label_.yDraw := button.label_.y - 1
else
button.clr.current := button.clr.highlight
button.boarder.clr.top_left := white
button.boarder.clr.bottom_right := black
if button.pressed then %if the mouse button is released but button.pressed is true, then the button has just been released
button.released := true
button.pressed := false
end if
button.label_.xDraw := button.label_.x
button.label_.yDraw := button.label_.y
end if
else
button.pressed := false
button.clr.current := button.clr.main
button.boarder.clr.top_left := white
button.boarder.clr.bottom_right := black
button.label_.xDraw := button.label_.x
button.label_.yDraw := button.label_.y
end if
if button.released then
button.released := false
result true
end if
end if
result false
end clicked
%hides the button so it cannot be seen or released
proc hide
button.show := false
end hide
%shows the button so it can be seen and released
proc show
button.show := true
end show
fcn visible : boolean
result button.show
end visible
end BUTTON
%example button
View.Set ("offscreenonly")
var button : ^BUTTON
new BUTTON, button
button -> INIT (maxx div 2, maxy div 2, 0, 0, 20, 7, "Test Button", "Times New Roman", 12, black, 26, 28, 24)
loop
if button -> clicked then
end if
cls
button -> draw
View.Update
delay (10)
end loop
|
|
|
|
|
|
|
|
|