views:

226

answers:

2

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

  1. 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")]

  2. create a blank canvas, double the width of the text extent

  3. 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 ridiculous 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.

+1  A: 

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.

Ryan Ginstrom
Thanks for your reply Ryan, I have tried using the double buffered method to stream the text, unfortunately no matter what I do I still get flicker when using excessively large fonts. I've been trying to use the same concepts to create a way to design an initial bitmap in wx. If I can draw the text out in wx I can avoid the wx/PIL facename/filename issue altogether. Then I can just convert the bitmap to a PIL image and then use the bitmap to create my individual GIF frames by pasting the image onto a new PIL image and slightly moving the text image to the left per frame.
AWainb
The problem I am running into here is how to write the bitmap out, re-size it to fit all of the text, and preferably be able to do all of this without having to display it to the user. With the DC methods I have found online, I have not seen one which describes how to draw the image behind the scenes like that, nor can I seem to find a "real" way to re-size the bitmap past the client size to contain all of the text. Only suggestion I have found is to over compensate the image size, which strikes me as a useless waste of memory.
AWainb
Created another post on the wxPython-users Google group: http://groups.google.com/group/wxpython-users/browse_thread/thread/4196bb8d26954d21
AWainb
A: 

I'm hitting this exact same issue. Thanks for the tip on the registry key, that seems to be working well, but I'm building an app that will be installed on some Vista 64 bit machines and for some reason I'm not able to read the registry from Python under Vista 64. And plus, its so kludgey having to removing all the extra strings from the font titles as they appear in the registry, it seems asking for trouble.

If possible, can you let me know if you find a solution? I'm at wrybread at gmail dot you know what. If you email me we can discuss.

Edit: this looks promising, but I can't figure out how to access it:

http://msdn.microsoft.com/en-us/library/dd144885(VS.85).aspx

Apparently its not wrapped by Python's win32api.

Wrybread
Sorry about the delayed response but I had to put this little project on hold for a bit. As per the post I made on wxpython-users, it appears it is not possible to properly link the facenames to the filenames.Although.. Using the suggestions made, I was able to draw the bitmap in wxpython, convert it to pil and create the animated gif. I will try to post an example within the next few days. With regards to your issue, it does not appear to be directly related to this question but if you can create a separate question for it I will be glad to help out where I can.
AWainb