wx.Font uses a facename & PIL.ImageFont uses a filename... Is there any way to relate the two?
Hey guys, sorry but this is going to be a big one.. ;)
I'm running into an annoying little snag right now. I'm creating an RSS-style app for work which will be placed on some large LCD displays across the office. The basic concept is to have a client/server setup where the user would use a custom editor to create the individual articles with their chosen fonts, weights, sizes, etc. and then upload them to the server which (originally) would display the text on the LCD screens using a wx.TextCtrl & wx.TextAttr.
Here is where I am going nuts..
I was able to create the client/server without a hitch, I can get the server's display to work correctly, but I am unable to find a method to stream the text from right to left without causing any flicker. Our displays are 42 inch and I have tried using quite a few methods to accomplish this task but with the text sizes needed for these display's I just can't seem to get rid of the flickering.
So far I have tried three methods to get the text in motion:
Method 1: wx.Ticker()
This is a control that appeared to do exactly what i have been trying to accomplish, and when using smaller fonts it actually does exactly what I need. The Problem is that we cannot use smaller fonts, the fonts we will be using will be quite large, like 36, 48, 72, etc. and when testing the ticker with the wxpython demo I was unable to create a smooth enough effect to consider this a feasible way to accomplish my task, even after tweaking their code a bit.
Method 2: FadingTextCtrl() (Custom control)
A while back, and well before I found the wx.Ticker, I had created a control to accomplish this feat and I have used it successfully within a few previous projects. I basically setup a TextCtrl with an EVT_TIMER, set the cursor to the beginning of the line and then repeatedly removed the first character of the text, speed is controlled by a EVT_TIMER. This surprisingly lessened the frequency of the flickering but when it did choose to flicker, it was much more noticeable. Another downfall is that you need to use a fixed-width font to avoid jumpiness when deleting characters. Without a fixed-width font, some characters will delete faster then others due to their changing widths, causing the motion of the text to appear to speed up & down randomly which makes it impossible to accurately control the speed.
Method 3: wx.AnimatedCtrl() & a custom generated animated GIF
This seems to be my best bet so far. AND I AM SOOOOOOOOO CLOSE!!!
Using PIL, and some random snippets I was able to find through Google along the way, I have been able to generate an animated GIF and place it in a wx.AnimatedCtrl(). After doing some testing on the big screens it FINALLY looked like I had my solution as the text streamed on by without a single flicker! After adding some more frames to the gif I was able to have the text move across more smoothly then with any of the previous methods. So here it is , no flickering, complete smoothness, and then the most ridiculous conflict slapped me silly...
After building a function suitable to create my images on demand I went back to my GUI and started to link all of my controls, gathering all of my text and their attributes to create the animated GIF with. I go to push it all to my function and then it strikes me that the way you would create your fonts in wx is different then the way you would with PIL, more specifically how you designate which font you plan to use for your text. For example, a wx.Font() uses the Facename of a font to designate the font to be used, where PIL.ImageFont uses a path/filename of the font to select the font to draw with.
You have to be kidding me..... I am now just one step away from completing my project and I get slapped with no way to relate my fonts. I can push the rest of the font information in but I can't tell PIL.ImageFont which font to use with the font data provided by wx.Font().
So finally, here's my question... How can I relate the facenames from wx.Font() with their actual filename's so I can find a way to tell PIL.ImageFont to use the text attributes I have defined with my controls?
I thought I hit the jackpot last night when I found the registry key:
"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts"
This key contains a bunch of string values which defines Window's available font facename's, and the relevant paths to their files. This is the same information used by Control Panel >> Fonts so you would think this was my missing link. I quickly built another module to index the values and produce the selected facename/filename for the text. This appeared to work just fine for the TTF (TrueType) fonts.
And then ANOTHER snag hits..
Most Facename's use multiple font files to produce effects like italic, bold, etc. but with wx.Font() it appears that you always use the one facename for the font, like "Tahoma", and designate the effects with other arguments like style, weight, etc. So for Tahoma regular, you would use the font file "TAHOMA.TTF" but to use Tahoma Bold you would use the font file "tahomabd.ttf". That being said, The facenames found in the registry do not properly match with the facenames used in wxPython. For example: regsitry facename for Tahoma can be either Tahoma (TrueType) or Tahoma Bold (True Type) for bold, although wx.Font() just wants "Tahoma" for both, and it will match the appropriate font files behind the scenes using the other arguments you provided to the control. It was easy to remove the junk text in the registry facename's, like (TrueType) or (VGA res), but I am still left with multiple facenames for certain fonts, which just doesn't fly.
Now here is where I am currently at.
I use PIL to create my animated gif by creating a canvas, setting all of the text attributes
create two lists, one for the text, one for the attributes for each text item. eg:
msgs = ["*** ", "Header: ", "The message body to print to the image file. What else is there to say?? REALLY?!?!?! WHAT IS THERE?!?", " ***"]
fonts = [(font_bold_file, 48, "#000000"), (font_bold_file, 48, "#000000"), (font_norm_file, 48, "#000000"), (font_bold_file, 48, "#000000")]
create a blank canvas, double the width of the text extent
- iterate through the lists, writing the text on the canvas, right-justified, slightly moving the text's posX to the left per frame.
To avoid the facename/filename conflict between wx.Font and PIL.ImageFont I was thinking I should first create a bitmap with the text and all of it's attributes in wxPython, then convert it to a PIL image. Then instead of drawing the text with PIL.ImageFont, moving the position of the text slightly over per frame, I should just paste the converted wxBitmap onto the canvas, slightly moving the whole bitmap over per frame using PIL.Image's paste?
The issue I am running into here is finding proper way to use any of wx's DC's (ClientDC, PaintDC, (Auto)BufferedDC, MemoryDC) to create the bitmap with. So far I am able to use a wxMemoryDC & wxBitmap to write the text to the bitmap but so far I cannot find a way to set the full VirtualSize of the bitmap to contain the whole image as it seems to be limited to the window's ClientSize. I would have designated the full size from the start but I do not have that information until I get the text extent of the message. In the long run I would prefer to create the wxBitmap without even displaying it in a control as it's only purpose will be to be passed to PIL for further processing.
So here is where I beg for help!! Can somebody PLEASE PLEASE shed some light on how I can can either find a way to relate wx.Font with PIL.ImageFont so I can just use my animated gif generator to do what it already is setup to do, or help shed some light on how I can create a bitmap using wxPython, as well as draw in my text so that all of the text is present within the bitmap, regardless of the current ClientSize? I can easily convert the bitmap to PIL, I just need to figure out how to create it in with wx first!
A HUGE THANKS IN ADVANCE to anyone that can help, and my apologies for the super long post, but I should have had this project complete weeks ago. This ridic开发者_运维技巧ulous font issue keeps slapping me around every time I think I've figured it out! Being it that this is a project for work, If you require any code samples please request and I'll whip something up without any work-related info in it.
Have you looked into using wx.MemoryDC with a double-buffered window (i.e. "bit blitting")? The basic technique is that you draw your text into the DC off-screen, and then "blit" it onto the screen. This eliminates flicker.
Here's a discussion about eliminating flicker in the wx wiki.
And here's a discussion of double buffering in the wxpython wiki.
Forgot to answer this long ago...
With regards to relating the fonts, in the long run I was not able to find a feasible method to accomplish this task.
Using the suggestions made by Christopher, I was able to generate an animated GIF with the specified text which cleared up the motion issue quite a bit.
Unfortunately I am unable to provide an example as this project was for a company I worked for a few years back and I do not have access to the source code at this time.
精彩评论