[RESOLVED] How to RESIZE a Picturebox with only TEXT in it?
I know how to resize a Picturebox which has a picture in it... duh.
But I have a picturebox, in which I am only inserting some text into it.
I establish the currentx and currenty; I establish the fontname, bold, etc.,
and the forecolor.
I then use the "print" method to place text in the picturebox.
Works great.
But I now want the picturebox to resize down (or up) to just big enough to hold the inserted text.
It does NOT have a picture in it.
I've been looking for days... can't find anything.
Re: How to RESIZE a Picturebox with only TEXT in it?
I just slapped this example together, uses DrawText API.
Code:
Option Explicit
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Const DT_CALCRECT = &H400
Private Const DT_WORDBREAK = &H10
Private Const DT_SINGLELINE = &H20
Private Declare Function DrawText Lib "user32.dll" Alias "DrawTextA" (ByVal hdc As Long, ByVal lpStr As String, ByVal nCount As Long, ByRef lpRect As RECT, ByVal wFormat As Long) As Long
Private Sub Command1_Click()
' test...
Dim rct As RECT
Dim mText As String
Dim i As Integer
' some text to draw
For i = 1 To 20
mText = mText & "<<<<<<< Test Line >>>>>>>> " & CStr(i) & vbCrLf
Next i
' size pic box to text
rct.Left = 0
rct.Top = 0
rct.Right = Picture1.ScaleWidth
rct.Bottom = Picture1.ScaleHeight
Picture1.Height = (DrawText(Picture1.hdc, mText, Len(mText), rct, DT_CALCRECT Or DT_WORDBREAK))
' draw the text
DrawText Picture1.hdc, mText, Len(mText), rct, DT_WORDBREAK
Picture1.Refresh
End Sub
Private Sub Form_Load()
' set scale to pixels
Me.ScaleMode = vbPixels
Picture1.ScaleMode = vbPixels
Picture1.AutoRedraw = True
End Sub
Re: How to RESIZE a Picturebox with only TEXT in it?
Edgemeal,
Thanks that's pretty good.
But it doesn't set the width.... only the height.
And... (I should have given more information)....
I am using graphics methods to draw on the picturebox....
specifically "Print".
That is because I am actually printing text on an angle (rotated).
To do this I use the "CreateFont" GDI funtion.
Then I draw the text (rotated).
Then restore the original font.
So I create the font using the CREATEFont GDI function.
Then I assign this new font to the Picturebox.
Then I set the currentx, currenty, fontname, size, bold, ete., and forecolor.
Then I do the Print.
Then I restore the original font.
(I am not including the declarations, etc... this is just to give an idea of
the code I am using)
Code:
newfont = CreateFont(lFontsize * 2, 0, _
lRotationangle, lRotationangle, _
bFontbold, _
bFontItalic, bFontUnderscore, _
bFontStrikeThru, 0, 0, _
16, 0, 0, "comic sans ms")
oldfont = SelectObject(Picture1.hdc, newfont)
Picture1.forecolor = vbMagenta
Picture1.Print "This is a test of Rotated Text"
newfont = SelectObject(Picture1.hdc, oldfont)
DeleteObject newfont
This works just fine... I get text rotated in the picturebox.
But now I want to resize the picturebox, to just be big enough to show that text.
Re: How to RESIZE a Picturebox with only TEXT in it?
It's be a bit slow, but you could use the GetPixel API and four sets of loops to find the top, bottom, left and right edges of the text.
I'm not going to write the whole thing, but I'll show you how to find the top edge.
Code:
Option Explicit
Private Declare Function GetPixel Lib "gdi32" (ByVal hDC As Long, _
ByVal x As Long, _
ByVal y As Long) As Long
Public Function FindTop(ByRef Pic As PictureBox, ByRef BackClr As Long) As Long
Dim lX As Long
Dim lY As Long
Dim bFound As Boolean
Dim cMode As ScaleModeConstants
'store the scalemode
cMode = Pic.ScaleMode
'set the picbox to pixels
Pic.ScaleMode = vbPixels
For lY = 0 To Pic.Height
For lX = 0 To Pic.Width
'search across the row to find a diff colored pixel
If GetPixel(Pic.hDC, lX, lY) <> BackClr Then
bFound = True
Exit For
End If
Next
If bFound Then Exit For
Next
If bFound Then
FindTop = lX
End If
Pic.ScaleMode = cMode
End Function
It's been a while, I can't remember if lX and lY should start at 0 or at 1.
Play with it and you'll figure it out.
Last edited by longwolf; Oct 16th, 2008 at 08:37 PM.
Re: How to RESIZE a Picturebox with only TEXT in it?
You may be able to get the text size this way
Code:
Pic.Font = xx 'put in your font
Pic.FontItalic = True ' or false
Pic.FontSize = xx 'put in your font size
'transpose the height and width since you're rotating the text
lWdth = Pic.TextHeight(YourText)
lHght = Pic.TextWidth(YourText)
If your text is going to be diagonal, I think you're stuck with the GetPixel method
Last edited by longwolf; Oct 16th, 2008 at 08:58 PM.
Re: How to RESIZE a Picturebox with only TEXT in it?
Longwolf, thanks so much for the suggestion.
The text will be pretty much anything but horizontal, considering I will allow the user to rotate it to any angle (0-360).
When I use your routine (getpixel) (I played with it for a few hours),
a couple of things arise:
1. After setting the scalemode to pixels, the picturebox width and height are still in twips.
At least the "next/for" loops are working with the original width and height numbers (in twips).
I tried to use "scalewidth" and "scaleheight", but these numbers were far less than even my original width and height....
Original width = 6000, Scalewidth = 397
So I am not sure if I should be converting things manually to a different scale, or ???
2. I keep getting a return from the GetPixel routine of -1.
This tells me that the region I am asking about is outside the "Clipping Region".
I have "ClipRegion" set to true, so I am not sure what this is all about.
3. I had to set the background color of the picturebox to a "palette" color.
A system color is always a negative number, and is therefore ALWAYS not matched in the first step of the two "Next/For" loops.
This is OK... I set it to white, figuring there will never be any white text on the picture.
So... I am stumped.
After some further thought regarding your logic...
So eventually I can find out the farthest extremities in the picturebox of where the angled/rotated text bounds are.
Now I have to "shrink" the bounds/borders of the picturebox to those numbers.
But I can't do that, because the text will move with the picturebox, essentially clipping off the text.
Somehow I have to move the text within the box, using those new numbers (I think).
Any further advice you can give would sure be appreciated.
(Or anyone else for that matter)
Re: How to RESIZE a Picturebox with only TEXT in it?
Try setting both the picturebox and it's form to pixels, unless you have some reason not to.
the point is, the scale must be in pixels for the API to work.
Once you know the bounds on the text, just repaint that section of the image into the top left corner of the picturebox and resize the picturebox.
the code will look something like this.
Code:
dim lWdth as long
dim lHght as long
lWdth = lRight - lLeft
lHght = lBottom - lTop
picPreview.PaintPicture picPreview.Picture, 0, 0, lWdth, lHght, lLeft, lTop, lWdth, lHght
'then resize the picPreview
picPreview.Height = lHght
picPreview.Width= lWdth
Re: How to RESIZE a Picturebox with only TEXT in it?
Originally Posted by Antithesus
I tried to use "scalewidth" and "scaleheight", but these numbers were far less than even my original width and height....
Original width = 6000, Scalewidth = 397
Actually, that's pretty close.
Most screens are set to 15 twips per pixel, so 6000/15 = 400
If your picturebox shows a boarder, that could account for the smaller size.
But I would have thought the diff would be an even number.
Re: How to RESIZE a Picturebox with only TEXT in it?
Originally Posted by Antithesus
Edgemeal,
Thanks that's pretty good.
But it doesn't set the width.... only the height.
To set the picbox height and width you could do it like this, but to calculate the area for drawing text on an angle I'm not sure how thats done. Best of luck!
Code:
Dim rct As RECT
Dim mText As String
Picture1.Cls ' (borderless pic box)
mText = "HELLO WORLD!"
' size pic box
DrawText Picture1.hdc, mText, Len(mText), rct, DT_CALCRECT Or DT_SINGLELINE
Picture1.Width = rct.Right
Picture1.Height = rct.Bottom
' draw the text
DrawText Picture1.hdc, mText, Len(mText), rct, DT_SINGLELINE
Picture1.Refresh
Re: How to RESIZE a Picturebox with only TEXT in it?
Wow, you guys have given me a lot more to work with.
Thanks.
Longwolf... dammit, I was (stupidly) under the impression that pixels were smaller than twips... so I thought those numbers were really wrong.
Thanks for clearing that up.
As for knowing the background color, that is not really necessary.... as the parameter I pass to the "GetTop" routine, I merely pass it the picturebox.backcolor property.
Any thoughts on why I am getting a -1 back from your routine?
Even when I start at 1 or greater... it still comes back with -1 for the very first GetPixel call.
Edgemeal, I'll look into your suggestions too.
I had also thought of a completely different approach... which I have implemented, and which does work... to a degree.
I have determined the textwidth and textheight of the string to be displayed,
based on setting the font, size, etc., etc.
Using geometry I calculate the new height based on rotating that text string with the number of degrees of rotation specified.
Armed with this info, I set the picturebox size, and THEN I do the "print" to place the text in the picturebox.
This caclulation is done because the rotation essentially crates a triangle, with a hypotenuse equal to the original textlength. I know the angle of rotation, so I can now calculate the new baselength, and the new vertical height. With a bit of "fudging" I have successfully made this work.
But, for any angle greater than 90 degrees, it gets real ugly. I have to move the starting point (axis of rotation) to the right, otherwise the text will extend left out of the picturebox.
And likewise for anything greater than 180 degrees..... I have to move the axis point upwards to stop from extending below the bottom of the picturebox.
This is why I am looking for something much less complicated.
OK... back to trying more of your stuff.... especially the "repaint" and "resize".
Re: How to RESIZE a Picturebox with only TEXT in it?
Originally Posted by Antithesus
Any thoughts on why I am getting a -1 back from your routine?
Even when I start at 1 or greater... it still comes back with -1 for the very first GetPixel call.
I finally broke down, made a test project and simplified the FindTop function.
I've tested it and it works fine on a pic box, with or without the boarder.
Code:
Public Function FindTop(ByRef Pic As PictureBox, ByRef BackClr As Long) As Long
Dim lX As Long
Dim lY As Long
Dim cMode As ScaleModeConstants
' 'store the scalemode
cMode = Pic.ScaleMode
'set the picbox to pixels
Pic.ScaleMode = vbPixels
For lY = 0 To Pic.ScaleHeight - 1
For lX = 0 To Pic.ScaleWidth - 1
'search across the row to find a diff colored pixel
If GetPixel(Pic.hDC, lX, lY) <> BackClr Then
FindTop = lY
Exit Function
End If
Next
Next
End Function
I don't know why your getting that -1 on the 1st pixel :/
try this one and see if it works
Edit: spotted a bug, that FindTop = lX needed to be FindTop = lY
I'm always getting my X's and Y's mixed up
Last edited by longwolf; Oct 17th, 2008 at 12:28 PM.
Longwolf, thanks for the "project".
I had actually gotten all that done by myself.
Created 3 more functions.
Figured out the correct X and Y, and had to initialize the boolean "bFound" for each function.
That is what was causing me to burp out with a -1.
And.. I am using a Picturebox, not an Image.
And... when using the "PaintPicture" method, if the Picturebox you are copying/painting from does NOT contain a "picture" (as in some image or bitmap) you get an ERROR.
So I have opted to use 2 pictureboxes, and I then do a BitBlt from one box to the other.
It all works GREAT.
Of course, I have spent most of today working on this, building a little test project I can set up for you to see.
One problem I am encountering....
To ensure the user-provided text actually fits in to the Picturebox, I resize it once I determine how long the text string is. I resize it to the same width and height as the text string, so I can actually fit it all into the picturebox.
Well, if during this resizing, the picturebox now overlays some other form objects....OhBoy... CRASH time. (I'm running Vista).
So I have spent the last few hours trying to figure out how to circumvent this issue.
The easiest solution is to limit the length of the text string, to ensure it fits into a maximum picturebox size.
But I would prefer to NOT do that.
So I am working on that process right now.
Once I get it all working pretty good, I'll post the project code for you (and anyone else who might be interested).
Re: [RESOLVED] How to RESIZE a Picturebox with only TEXT in it?
A few more tips for you.
Near the top of the sub add...
Code:
Picture2.Height = 3735
Picture2.Width = 4335
That will let you use the 'Do it' button more than once
Don't resize Picture1, that will help prevent most of the text loss
Your..
Select Case Rotateangle
needs work.
Picture1.CurrentX and Picture1.CurrentY set the point where the text will begin printing.
And set those 1's in the For/Next's back to 0.
I had it right the first time.
You seem sharp, but I get the impression that you're just beginning to learn VB6.
Now's the time to learn good coding conventions.
They'll pay off later, especially when you have to go back to one of your old apps and try to debug it
Here's something I posted a while back. http://www.vbforums.com/showpost.php...66&postcount=4
And there are a lot of other good posts on learning VB at this form.
Last edited by longwolf; Oct 17th, 2008 at 09:10 PM.
Re: [RESOLVED] How to RESIZE a Picturebox with only TEXT in it?
a little more constructive criticism,
These variables should be Dim'ed in the subs where they are used.
That would prevent the bFound problem you had.
Code:
Dim lX As Long
Dim lY As Long
Dim bFound As Boolean
Dim cMode As ScaleModeConstants
Dim ThisPixel
Dim Newtop
Dim NewLeft
Dim NewBottom
Dim NewRight
Dim Newheight
Dim NewWidth
Placing them in the Declaration section causes them to be held in memory no matter which sub your in.
That can be handy, but you want to limit the use to variables that need to be used that way.
For instance:
Dim PixelstoTwips
Could be be made a module level variable, if you needed it in some of your other subs.
That way you would only have to compute it once, usually in the Form_Load event.
And while Dim works in the Declaration section, you usually want to use Private or Public to declare vars there.
Last edited by longwolf; Oct 17th, 2008 at 09:55 PM.
Re: [RESOLVED] How to RESIZE a Picturebox with only TEXT in it?
Longwolf,
thanks for the hints.
As I said, I just wanted to give a sample of how it could be used, to show how it can be done.
I do know the Select case Rotateangle needs work.
But for my purposes I don't really need it.
I just built it in here so this could demonstrate that it CAN work.
I resized Picture1 to ensure it was at least large enough to handle a long text string. If it is not large enough, then the text gets clipped, and the results (in Picture2) are clipped off. So I tried to resize it according to the text being rotated.
For my REAL purposes, I am going to implement the logic into a "PrintPreview" facility I am building, which has the ability to export a Report to a PDF and/or a RTF.
It is the creation of rotated text for the RTF that was causing me all sorts of grief. All the rest is working fine.
As for Coding.... I've been writing applications since 1968.
(Good old IBM 1410/1401, System350, System360).
I've had my own PC since 1980. Can't count how many I've had/used.
I was the first person in Vancouver to have VB1.
I have been programmer, developer, development manager, MIS manager,
project manager, website developer, technical liaison, and on, and on, and on.
I can't remember how many languages I've learned/used (and forgotten a few).
Databases ...old GIS, MIS, SQL/DS, SQLServer, Cognos, Oracle, and on, and on.
There are many conventions that have come and gone during the years.
Some of your suggested coding practices are good.
I have learned from many past years, and sort of gotten into a routine about things.
But I will take your suggestions into consideration.
Re: [RESOLVED] How to RESIZE a Picturebox with only TEXT in it?
Originally Posted by Antithesus
As for Coding.... I've been writing applications since 1968.
(Good old IBM 1410/1401, System350, System360).
I've had my own PC since 1980. Can't count how many I've had/used.
I was the first person in Vancouver to have VB1.
I have been programmer, developer, development manager, MIS manager,
project manager, website developer, technical liaison, and on, and on, and on.
Wow, My apologies.
I've only been coding since the Tandy CoCo came out(128k ttl ram)
Re: [RESOLVED] How to RESIZE a Picturebox with only TEXT in it?
Longwolf,
maybe you can help me with an "issue" which I can't resolve with this routine.
I am attaching an updated version of the project, which allows for a bit more
user input, and which has better logic in placing the text string into the picturebox.
I have added some checkboxes, to allow the user to specify Bold, Italics, Underscore, and Strikethru.
So, run the app... either in development mode, or compiled to an .exe.
Click on the "Doit" button.... great, it rotates the text.
Just do this a few times, repeating the same stuff.
Now click on the "Bold" checkbox. Then "Doit". You might have to "Doit" a few times.
BANG... the font for the Bold checkbox now changes to bolded font.
And I think the fontname/face also is changed.
Now click on Italics checkbox. Then Doit... the Italics checkbox changes to bolded font.
Keep doing this with all check boxes... they change to bolded font.
Eventually the "Doit" button also changes.
If you are in development mode, and you then stop the program from running, the controls/objects on the form are STILL BOLDED font.
You actually have to close the project, and start it up again.
If you run the .exe, the same thing happens.
Something is walking all over something else.
I am running Vb6 (Visual Studio 6), with latest upgrades, Vista Ultimate,
on a pretty powerful (dual core, quad, 2.4GHZ, 4GB, 500GBDualRaid).
If you can figure this out, I would sure appreciate it. I am stumped.
Re: [RESOLVED] How to RESIZE a Picturebox with only TEXT in it?
That is weird.
I suspect that there's a problem with one of the API calls.
But I don't know these well, so I was unable to prevent the problem.
I did try adding a sub to re-set the fonts.
It seems to have prevented the font name and size changes.
But they are still going bold.
Also, the main sub still wasn't doing what it was meant to do, crop to the text.
There were two problems
1. The RGB values are wrong, so I set it to auto grab the backcolor
2. If the font was large, Picture2 wouldn't get it all, had to move the pic re sizing ahead of the BitBlt
So this upload fixes the cropping.
I'd recommend starting a new Thread to see if someone can help with the CreateFont problem, unless you can live with the small help I was on that part.
Re: [RESOLVED] How to RESIZE a Picturebox with only TEXT in it?
Originally Posted by Antithesus
The only other API I use is BitBlt. I hope that is not causing the problem,
because that is also paramount to having this work.
TTYL
Not quite right, you're also using SelectObject and DeleteObject.
I don't think it's BitBlt, but even if it was you could use Picture2.PaintPicture.
But the prob is likely to be in the CreateFont call.
That thing is a monster.
The most common API mistake is sending one of the parameters in the wrong variable format.
Hummmm, wait a sec.....
All the parameters, except the last one are suppose to be longs.
And you're sending some Integers and Booleans at it.
You might try fixing those.
There is a function in this list that takes a font and string as parameters and returns the size in pixels. All you have to do is use pythagorean theorem when done to generate the new dimensions.
When returning the text extent, this function assumes that the text is horizontal, that is, that the escapement is always 0. This is true for both the horizontal and vertical measurements of the text. Even if using a font specifying a nonzero escapement, this function will not use the angle while computing the text extentthe application must convert it explicitly.
Re: [RESOLVED] How to RESIZE a Picturebox with only TEXT in it?
Thanks again, guys.
With Edgemeal's info (in my other thread ... APIs), I have made it work just fine.
And Longwolf, I have changed those parameters to conform with the datatypes defined in the API.
Lord Orwell, I am using Pythagorean theorem in my (very) old original logic which I alluded to earlier. But this involved some inventive "fudging" in my logic to accommodate fontsize, rotation angle, etc.
That is why i have opted for this "newer" (not necessarily elegant) approach.
I use "Textwidth" and "TextHeight" which seems to return something which is reasonable for my purposes.
Again, thanks for the Interest, and help... to all of you.
Re: [RESOLVED] How to RESIZE a Picturebox with only TEXT in it?
Originally Posted by Antithesus
Thanks again, guys.
With Edgemeal's info (in my other thread ... APIs), I have made it work just fine.
And Longwolf, I have changed those parameters to conform with the datatypes defined in the API.
Lord Orwell, I am using Pythagorean theorem in my (very) old original logic which I alluded to earlier. But this involved some inventive "fudging" in my logic to accommodate fontsize, rotation angle, etc.
That is why i have opted for this "newer" (not necessarily elegant) approach.
I use "Textwidth" and "TextHeight" which seems to return something which is reasonable for my purposes.
Again, thanks for the Interest, and help... to all of you.
well that's where the textextentpoint api call would help you. It actually measures it for you. No guessing based on average sizes, etc.
Re: [RESOLVED] How to RESIZE a Picturebox with only TEXT in it?
Originally Posted by Lord Orwell
well that's where the textextentpoint api call would help you. It actually measures it for you. No guessing based on average sizes, etc.
You make it sound easy, I just can't grasp how you'd measure the height/width of text drawn on angles, I tried a couple things, none came close to a fix. Guess I should be glad I don't need to do it.
Re: [RESOLVED] How to RESIZE a Picturebox with only TEXT in it?
you wouldn't. You measure it as it was straight by feeding it the string you are going to draw. then you use the theorem to know the dimension at an angle. the documentation states this is the way they expect you to do it.
Re: [RESOLVED] How to RESIZE a Picturebox with only TEXT in it?
Hey guys, you have helped me immensely.
But (there's ALWAYS a BUT).
I see that the resultant cropped picturebox with the rotated text in it has an opaque background.
OK, here is what I am doing.....
I am trying to create a routine that will take a "Report" (which can consist of text, graphics, charts, pictures, ROTATED text, etc.), and export that to a RTF.
I have explored the wonderful world of RTF (the latest specifications),
and I can do it.
In fact I am doing it... INCLUDING the ROTATED text.
To create Rotated text, I MUST get it into an image/picture which essentially is a bitmap/WMF. I then extract the hexadecimal representation of that image, surround that with the necessary RTF control "stuff", and write it out to the RTF file.
This works quite good.
But the bitmap/wmf has an opaque background, therefore any rotated text which might come close or overlap anything else on the page obscures it, because the background is not transparent.
So.... how do I get my resultant cropped picturebox to have a transparent background ?
I have searched and found several threads which approach this, but they all work with a "picture" within a Picturebox. Remember, I don't have a picture in my Picturebox; I merely have some graphics.
So... should I try to use a different object ? (I have no idea what I could use... an Image won't work, because it doesn't have an hDC, so BitBlt won't work for it).
Any suggestions anyone can make would sure be appreciated.
Or even a totally different approach ?
(Maybe I should create a different thread ?)
Re: [RESOLVED] How to RESIZE a Picturebox with only TEXT in it?
you don't necessarily have to change anything about the picture box. But here's the problem: If you are storing it as a bitmap (.bmp), you can't give it a transparent background. Since you are already reading the hex value, perhaps you could store the data in a different uncompressed format that supports a background that is transparent, such as png. I suggest gif but i really don't know of an easy way to do this.
Re: [RESOLVED] How to RESIZE a Picturebox with only TEXT in it?
What I am doing, is reading the actual Picturebox.picture contents, using a routine I found on this site.
It does work very well.
So I don't store the picturebox.picture to any file or anything else.
And using Longwolf's suggestion, I can actually create a picture in the picturebox.
So...
1. Get rotated text into picturebox2, with bounds all set nicely.
2. Assign picturebox2.picture = picturebox2.image.
3. Use a routine to turn the background of the picturebox2 to transparent.
4. Use my Hex extraction routine to get the contents as a hex string.
Re: [RESOLVED] How to RESIZE a Picturebox with only TEXT in it?
Originally Posted by Antithesus
What I am doing, is reading the actual Picturebox.picture contents, using a routine I found on this site.
It does work very well.
So I don't store the picturebox.picture to any file or anything else.
And using Longwolf's suggestion, I can actually create a picture in the picturebox.
So...
1. Get rotated text into picturebox2, with bounds all set nicely.
2. Assign picturebox2.picture = picturebox2.image.
3. Use a routine to turn the background of the picturebox2 to transparent.
4. Use my Hex extraction routine to get the contents as a hex string.
Does it sound like this might work ?
Heck, I'll give a try.
it might be easier to switch 3 and 4 around. Replace the background with whatever code = transparent value while reading it. As far as i am aware, the control in vb6 is incapable of storing transparent images.
Last edited by Lord Orwell; Oct 21st, 2008 at 09:56 PM.